线程中的join方法,与synchronized和wait()和notify()的关系

什么时候要用join()方法?
1,join方法是Thread类中的方法,主线程执行完start()方法,线程就进入就绪状态,虚拟机最终会执行run方法进入运行状态.此时.主线程跳出start方法往下执行
2,两个线程以上,当一个线程需要另一个线程执行的结果时,可以在该线程之前调用另一个线程对象的join方法,如下:
public class TestThread {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadA("ThreadA");
Thread t2 = new Thread(new ThreadB(),"ThreadB");
t1.start();//主线程调用start方法,开启t1线程,
t1.join();//主线程调用join方法,获取对象t1对象锁,挂起主线程.直到t1线程结束
t2.start();//主线程调用start方法,开启t2线程
t2.join();//主线程调用join,获取t2对象锁,挂起主线程,直到t2线程结束
System.out.println(Thread.currentThread().getName()+"主线程结束");
}
}
如上代码,主线程一路下来调用其他线程的对象的join方法,就会被挂起直到该线程对象所在的线程结束.从而实现线程的顺序执行.
查看join的源码,该方法是同步方法,锁是t1线程所在对象的对象锁,我们可以看到,wait总是在synchronized代码块里面使用,并且在while循环中,有wait()就必然有notify()/notifyAll(),所以同样的一般情况下notify()/notifyAll()也是在synchronized代码块中的while使用的,synchronized,while,wait,notify结合可以实现经典的生产者消费者模式.
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
....
//主线程调用join方法就拥有了t1对象的锁,wait(0)一直处于等待状态,
//直到某个线程调用了该对象的notify或者notifyAll()
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
....
}
}
在join方法中我们看到了wait(),那么一定在某个地方有notify方法,该方法则在jvm源码中,这个段源码的作用是结束线程,在线程退出前需要做一些动作,其中就有调用notify_all的动作,看注释,还将isAlive变为false,
// 位于/hotspot/src/share/vm/runtime/thread.cpp中
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// ...
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
// 有一个贼不起眼的一行代码,就是这行
ensure_join(this);
// ...
}
static void ensure_join(JavaThread* thread) {
// We do not need to grap the Threads_lock, since we are operating on ourself.
Handle threadObj(thread, thread->threadObj());
assert(threadObj.not_null(), "java thread object must exist");
ObjectLocker lock(threadObj, thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
// Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED.
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
// Clear the native thread instance - this makes isAlive return false and allows the join()
// to complete once we've done the notify_all below
java_lang_Thread::set_thread(threadObj(), NULL);
// 唤醒其他线程
lock.notify_all(thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
}
由此我们即看到了notify,也看到了isAlive变为false,所以主线程再挂起的时候,会等待该对象线程t1结束并调用notify,唤醒之后则跳出循环检测isAlive为false则跳
出循环结束join方法,这就实现了线程的顺序执行,
码解读完毕
从代码中的while(isAlive){wait()}说起,
如果主线程在等待状态,被其他线程唤醒呢,所以前文我说,notify也一般配合synchronized,while使用,这个一般情况下是消费者生产者模式,但是在jvm源码中并没
有这么用,这是要等待t1线程结束前调用,所以这个isAlive就是保证一定被t1线程结束唤醒,而其他线程唤醒while判断之后再次进入挂起状态.
几个问题的辨析,
1,线程之间的竞争是同一个对象锁的竞争或者同一个类锁的竞争,与其他对象的锁无关.其他线程抢别的对象的锁,执行别对象的wait/notify方法都与竞争本对象
锁的线程无关.
2, 锁分为对象锁,类锁,锁的使用者叫线程,锁拦截的对象也是线程,不是什么方法,或者其他,.
对象锁,表示对象里面所有被synchronized(this)修饰的代码块和synchronized 修饰的普通方法块,不能同时被两个线程执行.详情见:synchronized的使用方法和作用域:
https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554746&idx=1&sn=8e45e741ca9f058dba1f3ebbea0e9f07&chksm=f3f833ecc48fbafa295e355c1cdd52dc4259f161dafdc1703d181a5e9f4f76563c98493bd221&token=2005887224&lang=zh_CN#rd
类锁是被synchronized(MyClass.class)和static synchronized 修饰的静态方法,不能同时被两个线程执行,详情见:synchronized的使用方法和作用域
https://mp.weixin.qq.com/s?__biz=MzI4NTEzMjc5Mw==&mid=2650554746&idx=1&sn=8e45e741ca9f058dba1f3ebbea0e9f07&chksm=f3f833ecc48fbafa295e355c1cdd52dc4259f161dafdc1703d181a5e9f4f76563c98493bd221&token=2005887224&lang=zh_CN#rd
3,线程释放锁的场景,
a,执行完同步代码块,
b,在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会被释放
c在执行同步代码块的过程中,执行了锁所属对象的wait方法,这个线程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒
notify和notifyAll的区别
我们首先得明确,一个对象只有一个锁,参与该对象锁竞争的线程,与参与其他对象锁竞争的线程无关.线程竞争,对应一个对象的一个锁.
有n个线程参与竞争同一对象的锁,t1率先抢到了锁,锁池中有n-1个线程在等待竞争锁,t1调用了wait()方法t1线程挂起,等待池中有一线程等待被唤醒.t2线程,获得了锁,锁池中有n-2个线程等待竞争锁,t2线程调用了wait方法挂起,等待池中有两个线程等待被唤醒,
此时t3线程获得了锁,
如果t3线程在同步代码块中调用的是notify则只会随机唤醒等待池中的一个线程移入锁池中参与锁竞争,有可能是t1,也有可能是t2,等待池中的线程为1
如果t3线程在同步代码块中调用的notifyAll,则会同时唤醒t1,t2移入锁池中参与竞争,等待池中的线程为零,
公众号:

线程中的join方法,与synchronized和wait()和notify()的关系的更多相关文章
- 模拟做饭系统(java+线程中的join方法)
(一)项目框架分析 妈妈要去做饭,发现没有酱油,让儿子去买酱油,然后回来做饭. 根据面向对象的思想,有两个对象,妈妈和儿子 主要有两个方法: (一)没有线程控制(即儿子没有买酱油回来妈妈就做好饭了)+ ...
- 线程中的join方法
join方法的作用是同步线程. 1.不使用join方法:当设置多个线程时,在一般情况下(无守护线程,setDeamon=False),多个线程同时启动,主线程执行完,会等待其他子线程执行完,程序才会退 ...
- 线程中的join()
http://blog.itpub.net/31555134/viewspace-2221319/ 一直对join()方法不是很理解,在A线程中, B线程调用了join()方法,然后在内部实际是wai ...
- Java多线程中的join()方法
一.join()方法介绍 join() 定义在Thread.java中.join()方法把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的join( ...
- Java并发编程--多线程中的join方法详解
Java Thread中, join()方法主要是让调用该方法的thread在完成run方法里面的部分后, 再执行join()方法后面的代码 例如:定义一个People类,run方法是输出姓名年龄. ...
- java线程学习之join方法
join()方法表示一个线程要加入另一个线程,直到被加入的线程执行完毕. 这个概念不好理解的话看面这个例子 public class TestJoin { public static void mai ...
- Thread类中的join方法
package charpter06; //类实现接口public class Processor implements Runnable { // 重写接口方法 @Override public v ...
- 3-等待线程终止的join方法
等待线程终止的join方法 在项目实践中经常会遇到一个场景,就是需要等待某几件事完成之后才能继续往下执行,比如线程加载资源等等. package com.heiye.learn1; public cl ...
- jQuery中的join方法
和JS 中的JOIN 方法一样,将一数组按照JOIN的参数连接起来.比如: var arr = [ "a", "b", "c", " ...
随机推荐
- cisco 交换机设置时区、时间、同步日志本地时间
Core-Switch-1#show clockCore-Switch-1#show ntp statusCore-Switch-1#conf tCore-Switch-1(config)# cloc ...
- Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)
一.自定义控件大全 (一).控件介绍 超过160个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...
- PMP 第8章错题总结
1.项目经理为项目的可交付成果定义验收标准.这些应记录在项目范围说明书2.项目的总体预算是“成本基准+管理储备”,成本基准里本身已包含了应急储备.工作包成本估算.活动成本估算3.范围基准包含----项 ...
- 零起点PYTHON足彩大数据与机器学习实盘分析
零起点PYTHON足彩大数据与机器学习实盘分析 第1章 足彩与数据分析 1 1.1 “阿尔法狗”与足彩 1 1.2 案例1-1:可怕的英国足球 3 1.3 关于足彩的几个误区 7 1.4 足彩·大事件 ...
- mysql的几个操作
1.忘记密码,从控制台免密码登录: 修改/etc/my.cnf,[mysqld]下加一行:skip-grant-tables 重启mysql: /etc/init.d/mysqld restart 命 ...
- 破解MySQL登录密码的几种方法
工具列表 Medusa Ncrack Hydra Metasploit Medusa medusa -h 192.168.1.106 –U /root/Desktop/user.txt –P /ro ...
- java内存模型,内存区域
Java虚拟机内存区域总结:Java虚拟机相当于一个抽象的计算机操作系统, 其管理的内从区域大体上可以分为栈和堆,就像c或c++中对内存的分类一样, 但这样的分类对于Java虚拟机来说太过粗浅, 实际 ...
- day21——面向对象初识、结构、从类名研究类、从对象研究类、logging模块进阶版
day21 面向对象的初识 面向对象第一个优点: 对相似功能的函数,同一个业务下的函数进行归类,分类. 想要学习面向对象必须站在一个上帝的角度去分析考虑问题. 类: 具有相同属性和功能的一类事物. 对 ...
- Vue框架——页面组件中使用小组件
小组件在components文件夹中,页面组件在views文件夹中 一.先写小组件的vue,比如text.vue(在template设置模板渲染,style设置样式) <template> ...
- ZYNQ笔记(1):PL端——led灯
ZYNQ分为PS和PL,此博客实际上是FPGA中一个完整的FPGA工程的创建. PS:处理系统 (Processing System) 即ARM的Soc部分 PL:可编程逻辑(Programable ...