什么时候使用异步?
处理多个任务,某些任务比较耗时,可以用异步。
异步线程
新建一个类,实现Callable接口,重写call()方法。
异步任务的结果,通过call()方法返回。
实现Callable 接口,call()结果就返回String类型。Object等其他类型同理。
如果不需要返回结果,可以实现Runnable接口,重写run()方法。
如果需要传递参数,可以写在构造方法中。
- 如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
public class AsyncTask implements Callable {
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(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 future = EXECUTOR.submit(asyncTask);
//也可以使用FutureTask,都可以用get()获取结果
// FutureTask 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 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.htmlhttps://www.cnblogs.com/cjsblog/p/9267163.html