[温故]图解java多线程设计模式(二)
一、join & interrupt
这俩方法属于线程对象里的方法,属于线程本身的操作。
1.1:join方法
用于等待一个线程的终止,等待期间将会阻塞,直到被等待的线程终止结束。
所以join可以用来做多任务异步处理,比如还是拿利用CompletableFuture优化程序的执行效率这篇里的第一个例子做优化,这篇文章里使用线程池的future模式进行多任务异步处理,现在使用join改写下:
再来简单贴下这几个方法
private String getTop() { // 这里假设getTop需要执行200ms
try {
Thread.sleep(200L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "顶部banner位";
}
private String getLeft() { // 这里假设getLeft需要执行50ms
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "左边栏";
}
private String getRight() { // 这里假设getRight需要执行80ms
try {
Thread.sleep(80L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "右边栏";
}
private String getUser() { // 这里假设getUser需要执行100ms
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "用户信息";
}
然后现在使用简单的线程做异步处理:
// 简单异步获取
public WebModule getWebModuleMsgSimpleAsync() throws ExecutionException, InterruptedException {
WebModule webModule = new WebModule();
Thread topTask = new Thread(() -> webModule.setTop(this.getTop()));
Thread leftTask = new Thread(() -> webModule.setLeft(this.getLeft()));
Thread rightTask = new Thread(() -> webModule.setRight(this.getRight()));
Thread userTask = new Thread(() -> webModule.setUser(this.getUser()));
//触发各个异步任务
topTask.start();
leftTask.start();
rightTask.start();
userTask.start();
//等待所有的任务均执行完毕
topTask.join();
leftTask.join();
rightTask.join();
userTask.join();
return webModule;
}
测试代码:
@Test
public void testSimpleASync() throws Exception {
// 同步方法测试,预估耗时200ms
long start = System.currentTimeMillis();
WebModule module = webHome.getWebModuleMsgSimpleAsync();
System.out.println("通过异步方法获取首页全部信息消耗时间:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("结果为:" + module.toString());
}
测试结果:
通过异步方法获取首页全部信息消耗时间:272ms
结果为:top: 顶部banner位; left: 左边栏; right: 右边栏; user: 用户信息
比预估的要多72ms,经过后来的测试,发现这72ms耗时发生在线程创建的时候,以及后续线程状态转换带来的消耗,下面等待异步结束的时间约等于200ms,符合预期。
1.2:interrupt方法
用于主动终止一个线程,线程本身调用该方法后,视为已终止状态,join解除阻塞,下面来用interrupt和join来做个实验:
public class JoinTest {
private boolean isStop = false;
public static void main(String[] args) throws Exception {
JoinTest test = new JoinTest();
Thread loopT = new Thread(test::loopTask);
loopT.start();
sleep(2000L); //2s后终止线程
test.setStop(true);
long s = System.currentTimeMillis();
loopT.join();
System.out.println("线程终止后,join阻塞时间为:" + (System.currentTimeMillis() - s));
System.out.println("end~");
}
public void setStop(boolean stop) {
isStop = stop;
}
public void loopTask() {
while (!isStop) { //若状态为false,则继续执行下面的逻辑,每隔1s打印一次
sleep(1000L);
System.out.println("loop trigger ~");
}
Thread.currentThread().interrupt(); //在这里终止掉当前线程
//事实上,在终止掉线程后,还有接下来的逻辑要执行
long s = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
int[] a = new int[100]; //模拟耗时操作,这里不能用sleep了,因为当前线程已经被终止了
}
System.out.println("线程终止后,逻辑块运行时间:" + (System.currentTimeMillis() - s));
}
public static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:
loop trigger ~
loop trigger ~
线程终止后,逻辑块运行时间:129
线程终止后,join阻塞时间为:129
end~
即便线程被终止了,后面的逻辑也会触发,join依旧会选择阻塞,直到后续逻辑执行完毕,事实上,大部分任务都可以及时的终止,比如第一个例子,异步出去的任务,最终都会执行完成,线程变为终止状态,join都可以顺利结束,但是反观上例,如果没人及时的设置isStop的值,程序会一直执行下去,没有终止态,join会无止境的终止下去,这里提一下stop,线程的stop方法已被官方标记为“不建议使用”的方法,如果把上例的interrupt的调用换成stop,来看看其运行结果:
loop trigger ~
loop trigger ~
线程终止后,join阻塞时间为:0
end~
可以看到,线程终止后的后续逻辑均没有触发,等于说stop是一种很粗暴的终止线程的方式,一旦被stop,那么里面的业务逻辑将直接断掉,因此官方并不推荐使用该方法来终止线程。
而interrupt,仅仅是对目标线程发送了了一个中断信号(改变了线程的中断状态而已),当目标线程再次通过obj.wait、thread.sleep、thread.join方法进入阻塞状态时,接收到该信号,就会抛出InterruptedException异常,这时候需要业务方自行处理或者直接抛出,以结束线程阻塞状态(这里需要注意的是被obj.wait方法阻塞时,抛出该异常需要目标线程再次获得实例对象obj的锁才行)。
上述三个“需要花费时间”的方法均抛出了InterruptedException异常,针对这些特性,想要完成以下操作就非常方便了:
①取消wait方法等待notify/notifyAll的处理
②取消在sleep方法指定时间内停止的处理
③取消join方法等待其他线程终止的处理
取消之后所做的处理,取决于需求,可能会终止线程,或者通知用户已取消,或者终止当前处理进入下一个处理阶段。
二、线程状态迁移图

图1
上面的图太多太杂,我们通过对一些可以影响线程状态的操作的分类,来简化一下上面的图:

图2
[温故]图解java多线程设计模式(二)的更多相关文章
- [温故]图解java多线程设计模式(一)
去年看完的<图解java多线程设计模式>,可惜当时没做笔记,导致后来忘了许多东西,打算再温习下这本书,顺便在这里记录一下~ 1.顺序执行.并行.并发 顺序执行:多个操作按照顺序依次执行. ...
- 《图解Java多线程设计模式》读书笔记
略读中...后面详读的时候,补充经典图片和文字说明
- 图解java多线程设计模式之一一synchronized实例方法体
synchronized实例方法体和synchronized代码块 synchronied void method(){ ....... } 这个等同于下面将方法体用synchronized(this ...
- java多线程设计模式
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt220 java多线程设计模式 java语言已经内置了多线程支持,所有实现Ru ...
- Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...
- 简述Java多线程(二)
Java多线程(二) 线程优先级 Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行. 优先级高的不一定先执行,大多数情况是这样的. 优 ...
- Java多线程(二) —— 线程安全、线程同步、线程间通信(含面试题集)
一.线程安全 多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不存在执行结果的二义性,就可以称作是线程安全的. 讲到线程安全问题,其实是指多线程环境下对共享资源的访问可能会 ...
- java多线程系列(二)
对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...
- java多线程系列(二)---对象变量并发访问
对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...
随机推荐
- Java 设计模式系列(十四)命令模式(Command)
Java 设计模式系列(十四)命令模式(Command) 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复 ...
- 08 Translating RNA into Protein
Problem The 20 commonly occurring amino acids are abbreviated by using 20 letters from the English a ...
- thinkphp+redis+队列
1,安装redis,根据自己的php版本安装对应的redis扩展(此步骤简单的描述一下) 1.1,安装 php_igbinary.dll,php_redis.dll扩展此处需要注意你的php版本如图: ...
- Git config 配置文件
一.Git已经在你的系统中了,你会做一些事情来客户化你的Git环境.你只需要做这些设置一次:即使你升级了,他们也会绑定到你的环境中.你也可以在任何时刻通过运行命令来重新更改这些设置. Git有一个工具 ...
- Template Method Design Pattern in Java
Template Method is a behavioral design pattern and it’s used to create a method stub and deferring s ...
- Android-无序广播
在之前的博客,Android-广播概念,中介绍了(广播和广播接收者)可以组件与组件之间进行通讯,有两种类型的广播(无序广播 和 有序广播),这篇博客就来讲解无序广播的代码实现: 无序广播:接收者 同时 ...
- [记]Centos下流量统计使用记录
因为最近要进行centos流量统计,需求是想针对tomcat进行针对性的上下行流量时段统计及汇总,找了很多资料及命令,要么是可以针对进程的但是没有汇总,要么是有汇总但是不针对进程. 所以只能混合几个命 ...
- wp8.1 调用智慧天气SmartWeatherAPI
在调用api应用的过程,我们需要用hmac加密技术,它是一种基于hash的加密算法,通过一个双方共同约定的密钥,在发送message前,对密钥进行了sha散列计算,在生成消息又对此密钥进行了二次加密, ...
- 浏览器兼容性随手记:Javascript
1.event IE9以下不支持直接获取event对象,所以需要写兼容: var event = event?event:window.event; IE8以下不支持event.target,但是可以 ...
- Android应用安全解决方案
Apk安全解决方案 背景 公司为政府做的App开发完了,需要上一些手段保证安全.这样客户才放心嘛. 防止第三方反编译篡改应用,防止数据隐私泄露,防止二次打包欺骗用户. 目录 Apk安全解决方案 背景 ...