java线程池异步

什么时候使用异步?

处理多个任务,某些任务比较耗时,可以用异步。

异步线程

新建一个类,实现Callable接口,重写call()方法。
异步任务的结果,通过call()方法返回。
实现Callable接口,call()结果就返回String类型。Object等其他类型同理。
如果不需要返回结果,可以实现Runnable接口,重写run()方法。
如果需要传递参数,可以写在构造方法中。

  • 如下:
package com.sf.inc.oewm.service.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;

public class AsyncTask implements Callable<String> {

    private String param;

    //构造方法传递参数
    public AsyncTask(String param) {
        this.param = param;
    }

    public String call()  {
        String result = null;
        try {
            result = doSomething(param);
            //休眠线程,是为了比较异步的时间,实际不需要用到
            Thread.sleep(4000);
        } catch (Exception e) {
            System.out.println("AsyncTask error.");
        }

        return result;
    }

    public String doSomething(String param)  {
        System.out.println("异步的参数:" + param);
        System.out.println("执行异步方法.");
        return "异步结果";
    }

}

线程池

使用线程池,将任务提交到线程池中处理。
submit()方法,会返回一个Future类型的对象。
而Future.get()方法,可以取得异步任务的结果,也可以使用FutureTask.
使用Future.get()后,主线程会阻塞,直到获得异步的结果,记得设置超时时间。

import java.util.concurrent.*;

public class SubmitTest {
    //定义线程池
    public static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor
            (5, 10, 100, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(60),
                    Executors.defaultThreadFactory(),
                    new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) throws  InterruptedException {
        submitTask();
    }

    public static void submitTask() throws InterruptedException {
        System.out.println("准备异步测试.");
        long t1 = System.currentTimeMillis();

        AsyncTask asyncTask = new AsyncTask("参数1");
        System.out.println("将任务提交到线程池.");
        Future<String> future = EXECUTOR.submit(asyncTask);
        //也可以使用FutureTask,都可以用get()获取结果
//        FutureTask<String> futureTask = new FutureTask<>(asyncTask);
//        EXECUTOR.submit(futureTask);

        System.out.println("还没进行future get().");
        //休眠线程,是为了比较异步的时间,实际不需要用到
        Thread.sleep(2000);

        String result= null;
        //使用future.get()阻塞,等待结果,并设置超时时间
        try {
            result = future.get(5,TimeUnit.MINUTES);
        } catch (Exception e) {
            System.out.println("future get overtime.");
        }
        System.out.println("future get()得到的结果:" + result);
        System.out.println("总共消耗时间 : " + (System.currentTimeMillis() - t1));
        //实际操作不一定要shutdown
        EXECUTOR.shutdown();
    }
}

执行结果如下:

准备异步测试.
任务提交到线程池.
还没进行future get().
异步的参数:参数1
执行异步方法.
future get()得到的结果:异步结果
总共消耗时间 : 4008

可以看到,我们在main()方法中休眠了2秒,在异步任务中休眠了4秒,最终全部消耗的时间只有4秒多。
通过异步,提高了处理任务的效率。

java8的线程池异步

如果异步任务不需要传递参数,可以直接使用lambda表达式,隐藏Callable实现类。

    public void submitTaskNoParam() throws ExecutionException, InterruptedException {
        //实战建议使用ThreadPoolExecutor自定义线程池,避免OOM,此处是为了方便示例
        ExecutorService executor = Executors.newFixedThreadPool(5);
        Future<String> future = executor.submit(() -> {
            System.out.println("执行异步任务.");
            return "异步结果";
        });
        String result = future.get(5,TimeUnit.MINUTES);
        System.out.println(result);
    }

参考资料:

https://www.cnblogs.com/expiator/p/14751838.html
https://www.cnblogs.com/cjsblog/p/9267163.html

原文地址:https://www.cnblogs.com/expiator/p/14750525.html