最近因为换了工作,新工作需要更多的时间熟悉和上手,所以好久没有写文章了!
不过其实也一直有在看一些东西,比如Netty,spark源码(其实以前有看过,但是太囫囵吞枣忘得差不多了) ,然后想起我以前写过一个线程池相关的文章,但是对于线程池的使用只是一笔带过,所以今天想具体来写写
【java】线程池概念,如何使用线程池?:https://blog.csdn.net/lsr40/article/details/101428779
曾经做过这么一个案例,就是通过用户传入的参数,实时构建一份数据报表,这个功能肯定是异步的,相当于用户调用了一个create方法把参数传入进来,就直接返回了,不过后台会启动第一个线程池,来根据获得的参数实际查数据库,创建数据报表,保存到数据库,然后又启动了一个线程池(回调方法),这个线程池里面使用了Future的get方法来等待第一个线程池完毕,并且将create的记录修改为成功或者失败,并且记录相关原因!
话不多说!下面,我会用六个例子,来演示Future的用法(我上面说的案例,用的是第五种模型,只不过FutureTask我们又自己封装了一层,在里面做了时间的记录,日志的打印,或者一些前置的初始化操作等待)
package com.study.asyn;
import java.util.concurrent.*;
/**
* Created with IntelliJ IDEA
* Description:
* User: lsr
* Date: 2020/6/15
* Time: 18:46
*/
public class FutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
System.out.println("主线程开始工作:");
long startTime = System.currentTimeMillis();
ExecutorService executorService = Executors.newFixedThreadPool(1);
//newThreadDemo(executorService);
//futureGetDemo(executorService);
//futureGetAndTimeOutDemo(executorService);
//futureGetAndCallableDemo(executorService);
//callbackDemo(executorService);
futureTaskDemo(executorService);
long stopTime = System.currentTimeMillis();
System.out.println("主线程结束,耗时:"+(stopTime - startTime)+"ms");
//关闭线程
executorService.shutdown();
}
/**
* 第一种,无所谓线程执行是否结束,不阻塞
* 打印结果:
* 主线程开始工作:
* 主线程结束,耗时:3ms
* 线程中的任务,开始运行!
* 正在执行!
* 线程中的任务,结束执行!
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void newThreadDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
executorService.submit(new Runnable() {
public void run() {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
}
});
}
/**
* 第二种,通过future的get方法,会阻塞等到执行完毕!
* 主线程开始工作:
* 线程中的任务,开始运行!
* 正在执行!
* 线程中的任务,结束执行!
* null
* 主线程结束,耗时:3005ms
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void futureGetDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
Future> future = executorService.submit(new Runnable() {
public void run() {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
}
});
Object o = future.get();
System.out.println(o);
}
/**
* 第三种,通过future的get方法,并且有超时时间,会阻塞等到执行完毕!
*
* 主线程开始工作:
* 线程中的任务,开始运行!
* 正在执行!
* 主线程结束,耗时:1007ms
* java.util.concurrent.TimeoutException
* at java.util.concurrent.FutureTask.get(FutureTask.java:205)
* at com.study.asyn.FutureTest.futureGetAndTimeOutDemo(FutureTest.java:99)
* at com.study.asyn.FutureTest.main(FutureTest.java:21)
* 线程中的任务,结束执行!
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void futureGetAndTimeOutDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
Future> future = executorService.submit(new Runnable() {
public void run() {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
}
});
Object o = null;
try {
o = future.get(1,TimeUnit.SECONDS);
System.out.println(o);
} catch (TimeoutException e) {
//true和false的区别大家可以看源码中的注释
//true就是中断当前执行的线程,false就是让线程执行完
future.cancel(false);
e.printStackTrace();
}
}
/**
* 第四种,通过future的get并且配合Callable方法,获得线程中return结果,会阻塞等到执行完毕!
* 主线程开始工作:
* 线程中的任务,开始运行!
* 正在执行!
* 线程中的任务,结束执行!
* 返回值~
* 主线程结束,耗时:3005ms
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void futureGetAndCallableDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
Future> future = executorService.submit(new Callable() {
public String call() throws Exception {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
return "返回值~";
}
});
String returnValue = (String)future.get();
System.out.println(returnValue);
}
/**
* 第五种,想在获得future的get结果之后,再做一些处理,但是又不想阻塞主线程,通过回调,启动另一个线程来做这个事情
*
* 主线程开始工作:
* 线程中的任务,开始运行!
* 正在执行!
* 主线程结束,耗时:5ms
* 线程中的任务,结束执行!
* 返回值~
* 成功!
*
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void callbackDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
ExecutorService fixExecutorService = Executors.newFixedThreadPool(1);
final Future> future = executorService.submit(new Callable() {
public String call() throws Exception {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
return "返回值~";
}
});
fixExecutorService.submit(new Runnable() {
public void run() {
String returnValue = null;
try {
returnValue = (String)future.get();
System.out.println(returnValue);
System.out.println("成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
});
fixExecutorService.shutdown();
}
/**
* 第六种,之前线程都是使用submit提交任务,以此获得返回Future对象
* 但是使用升级版的FutureTask+线程池的execute方法,也能得到返回值
*
* 主线程开始工作:
* 线程中的任务,开始运行!
* 正在执行!
* 线程中的任务,结束执行!
* 返回值~
* 主线程结束,耗时:3005ms
*
* @param executorService
* @throws ExecutionException
* @throws InterruptedException
*/
private static void futureTaskDemo(ExecutorService executorService) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(new Callable() {
public String call() throws Exception {
System.out.println("线程中的任务,开始运行!");
doSomeThing();
System.out.println("线程中的任务,结束执行!");
return "返回值~";
}
});
//execute方法虽然没有返回值,但是因为FutureTask实现类Future+Runnable,
// 所以也可以直接调用execute方法计算,再调用get获得返回结果
executorService.execute(futureTask);
String s = futureTask.get();
System.out.println(s);
}
private static void doSomeThing(){
try {
System.out.println("正在执行!");
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
好了,没有什么多余的东西要在这篇文章里说明了(每一种方法我都写好了注释,我也都跑过了,没什么问吐),大家要是有什么疑问,欢迎留言!
刚开始工作的时候,觉得有些人做一些朝九晚五不过钱少的工作,看起来一点都不nice,实际自己工作了几年之后,认真想想那样的生活又何尝不痛快呢?大家都在享受人生,千人千面,有人因为工作有所成就而快乐,有人因为爱好有所精进而快乐,有人因为教书育人而快乐,又有人因为游戏涨段而快乐,其实只要收入能够维持自己物质上支出,那做什么又有什么区别呢?并没有那么多人想在工作中,实现自己的理想和抱负,完成个人价值的升华。
想起初中语文老师问我,以后的目标是什么?
读好书,做好人,生好下一代,培养之,那这辈子的使命不也算完成了?
有时候躺在草地上,呆呆的望向天空,轻柔的云朵,绵绵的细雨,徜徉在花海中,感受大自然高山流水,又何尝不是一种人生哲学呢?
下班了,溜了溜了!