JAVA并发-join
概念
join方法,一种特殊的wait,当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到调用join方法的线程结束,再继续执行。
一般情况下,都是主线程创建一个子线程,子线程调用join方法,主线程会进入阻塞状态,直到子线程运行结束。
简单案例
public class JoinThreadDemo {
public static void main(String[] args) {
JoinRunnable runnable1 = new JoinRunnable();
Thread thread1 = new Thread(runnable1, "线程1");
System.out.println("主线程开始执行!");
thread1.start();
// try {
// thread1.join();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("主线程执行结束!");
}
static final class JoinRunnable implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
for (int i = 1; i <= 5; i++) {
System.out.println(name + "执行了[" + i + "]次");
}
}
}
}
Output:
主线程开始执行!
主线程执行结束!
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
取消注释,调用join方法:
主线程开始执行!
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
主线程执行结束!
替代join案例
public class JoinThreadDemo {
public static void main(String[] args) {
JoinRunnable runnable1 = new JoinRunnable();
Thread thread1 = new Thread(runnable1, "线程1");
System.out.println("主线程开始执行!");
thread1.start();
try {
synchronized (thread1) {
while (thread1.isAlive()) {
System.out.println("begin wait");
//主线程持有thread1对象锁,阻塞,一直到thread1运行结束,jvm唤醒
thread1.wait(0);
System.out.println("thread wait");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行结束!");
}
static final class JoinRunnable implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
for (int i = 1; i <= 5; i++) {
System.out.println(name + "执行了[" + i + "]次");
}
}
}
}
Output:
主线程开始执行!
begin wait
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
thread wait
主线程执行结束!
在thread1调用wait后,主线程阻塞,一直到子线程thread1运行结束退出以后,jvm会自动唤醒阻塞在thread1对象上的线程
那么有没有可能不使用thread1对象阻塞呢?
下面就是不使用thread1对象阻塞主线程的案例
替代join案例2
public class JoinThreadDemo {
public static void main(String[] args) {
Object lock = new Object();
Thread thread1 = new Thread(() -> {
String name = Thread.currentThread().getName();
System.out.println(name + "开始执行!");
for (int i = 1; i <= 5; i++) {
System.out.println(name + "执行了[" + i + "]次");
}
}, "线程1");
System.out.println("主线程开始执行!");
thread1.start();
//thread2自旋唤醒阻塞在lock对象上的主线程
Thread thread2 = new Thread(new Thread() {
@Override
public void run() {
while (!thread1.isAlive() && !Thread.currentThread().isInterrupted()) {
synchronized (lock) {
System.out.println("enter");
lock.notifyAll();
System.out.println("exit");
}
}
}
}, "线程2");
thread2.start();
try {
synchronized (lock) {
while (thread1.isAlive()) {
System.out.println("bb");
lock.wait();
//停止thread2自旋
thread2.interrupt();
System.out.println("tt");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行结束!");
}
}
Output:
主线程开始执行!
bb
线程1开始执行!
线程1执行了[1]次
线程1执行了[2]次
线程1执行了[3]次
线程1执行了[4]次
线程1执行了[5]次
enter
exit
enter
exit
tt
主线程执行结束!
这里添加了一个线程thread2用于专门自旋唤醒主线程
用于替换案例一中的,thread1线程结束后,jvm唤醒主线程操作
join原理
阻塞主线程
Thread类中,join源码:
//Thread类中
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis(); //获取当前时间
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) { //这个分支是无限期等待直到b线程结束
while (isAlive()) {
wait(0);
}
} else { //这个分支是等待固定时间,如果b没结束,那么就不等待了。
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
join成员方法中有synchronized,锁定的对象为调用该方法的对象,即子线程thread1,即主线程持有了thread1对象锁
可以自己调试,发现进入到join源码的线程为主线程
唤醒主线程
子线程thread1执行完毕的时候,jvm会自动唤醒阻塞在thread1对象上的线程,在我们的例子中也就是主线程。至此,thread1线程对象被notifyall了,那么主线程也就能继续跑下去了
参考
who and when notify the thread.wait() when thread.join() is called?
JAVA并发-join的更多相关文章
- java并发:join源码分析
join join join是Thread方法,它的作用是A线程中子线程B在运行之后调用了B.join(),A线程会阻塞直至B线程执行结束 join源码(只有继承Thread类才能使用) 基于open ...
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt
Java并发编程中,其中一个难点是对线程生命周期的理解,和多种线程控制方法.线程沟通方法的灵活运用.这些方法和概念之间彼此联系紧密,共同构成了Java并发编程基石之一. Java线程的生命周期 Jav ...
- Java并发编程原理与实战二十一:线程通信wait¬ify&join
wait和notify wait和notify可以实现线程之间的通信,当一个线程执行不满足条件时可以调用wait方法将线程置为等待状态,当另一个线程执行到等待线程可以执行的条件时,调用notify可以 ...
- 【转】Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
一.线程的状态 Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态). New:新建状态,当线 ...
- Java 并发编程 -- Fork/Join 框架
概述 Fork/Join 框架是 Java7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.下图是网上流传的 Fork Join 的 ...
- Java并发编程(07):Fork/Join框架机制详解
本文源码:GitHub·点这里 || GitEE·点这里 一.Fork/Join框架 Java提供Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务 ...
- Java并发——Fork/Join框架
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...
- Java并发——Fork/Join框架与ForkJoinPool
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...
随机推荐
- 2.Python学习之路
这里主要更新Python每个部分知识点的详细的目录...(知识点目录) Python基础 一.计算机基础 二.Python基础 三.函数 四.常用模块 五.模块和包 六.面向对象 Python进阶 七 ...
- DingTalk钉钉消息推送(.net core 3 WebApi尝鲜记)
我发了个朋友圈,Swagger真他妈的牛B,解放了开发API的码农,麻麻再也不用担心我们写API文档耽误回家吃饭了. /// <summary> /// 发送钉钉消息 /// </s ...
- 社招C++后台面试-拿到offer
社招C++后台面试-拿到offer 之前在一家小公司上班,主要是做C语言的嵌入式软件开发,涉及过一点点C++.工作大概三年,然后去试试大公司,这个面试题是我拿到offer后4个月才拖拖拉拉的开始写,题 ...
- Installing Google Chrome in Linux(RedHat Enterprise Linux 7)
# wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm # yum -y install r ...
- Guarded Suspension设计模式
Guarded Suspension 设计模式可以保证,当线程在访问某个对象时,发现条件不满足,就挂起等待条件满足时再次访问 public class GuardedSuspensionQueue { ...
- Sentry异常捕获平台
本文包括Sentry平台的介绍,以及环境搭建两部分,更多细节请查阅官方文档. 简介 Sentry是一个实时事件的日志聚合平台.它专门监测错误并提取所有有用信息用于分析,不再麻烦地依赖用户反馈来定位问题 ...
- TortoiseSVN客户端更改新的URL和账号
一: 变更SVN地址 右键(TortoiseSVN) → Relocate → 输入你新的URL地址 二:变更账号 TortoiseSVN右键->Setting 进入“Setting”之后,也就 ...
- 在VB编程中,若一行代码太长需要换行时,行尾要加什么符号
& _ 注意,&与_之间一定要有一个空格 例如: aa="select " & _ " a,b,c" & _ ...
- 架构师小跟班:如何高效又安全的清理Linux服务器上的缓存?
操作服务器上的生产环境,一定要慎之又慎,安全第一,优化第二! 一些基本原理 说到清理内存,那么不得不提到/proc这一个虚拟文件系统,这里面的数据和文件都是内存中的实时数据,很多参数的获取都可以从下面 ...
- 关于Git的用法
关于Git Git 是一个分布式版本控制软件,与CVS.Subversion一类的集中式版本控制工具不同,它采用了分布式版本库的作法,不需要服务器端软件,就可以运作版本控制,使得源代码的发布和交流极其 ...