JAVA多线程:狂抓 join()方法到底会不会释放锁,给你彻底介绍清楚(三)_join会释放锁吗-程序员宅基地

技术标签: # java多线程  java  java多线程  Java编程开发  后端  开发语言  

前言

了解这个问题前,先了解锁的概念:

锁,这个概念比较抽象,拿到锁,就意味着拿到了CPU的执行权

拿3个人看电视来说,锁就好比遥控。

A拿到遥控了,如果A仅仅是想休息一会儿,并不想放弃遥控的持有权),那么就调用sleep(1000)方法。然而,管理员来了,对A说,你立刻、马上把遥控交给我,并且N秒内,不得再拥有遥控,此时就调用wait(10000)方法,调用wait后A会立刻丢失遥控的所有权(直到10秒后才会参与再次竞争),此时剩余的所有人立刻会按优先级,重新争取(锁)遥控的持有权。 

概述

针对于这个问题,相信很多在使用多线程的人,都搞的不是很清楚,一直被这个问题困扰。

先说结论

join底层调用的是wait(),而wait是Object的方法,wait本身是会释放锁(彻底交出CPU的执行权),所以 Thread 的join() 方法是否会释放锁?答案是

但是,join()只会释放Thread的锁,不会释放线程对象的锁(可能会造成死锁)

相信很多人看到这个答案,比较绕口,看了很懵逼,上代码(代码很简单,耐心一点哦

一、示例代码

public class ThreadJoinTestLock {

	public static void main(String[] args) {
		Object object = new Object();
		MThread mythread = new MThread("mythread ", object);
		mythread.start();
		//synchronized (mythread)
		synchronized (object) {
			for (int i = 0; i < 100; i++) {
				if (i == 20) {
					try {
						System.out.println("开始join");
						mythread.join();//main主线程让出CPU执行权,让mythread子线程优先执行
						System.out.println("结束join");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() +"==" + i);
			}
		}
		System.out.println("main方法执行完毕");
	}
}

class MThread extends Thread {
	private String name;
	private Object obj;
	public MThread(String name, Object obj) {
		this.name = name;
		this.obj = obj;
	}
	@Override
	public void run() {
		synchronized (obj) {
			for (int i = 0; i < 100; i++) {
				System.out.println(name + i);
			}
		}
	}
}

二、运行结果

2.1、main方法对object添加锁,代码卡死在20不动了,造成死锁(不释放锁)

注:运行前,需要确保上述代码中的main方法中的代码同步块是object,如下所示!

synchronized (object)

可以看到,在join之前,一直是主线程在执行,main方法中的for循环到20时,此时该join方法的作用是让main主线程阻塞,给被join的线程让出CPU的执行权,让子线程mythread先执行。

但是,结局很意外,main方法的object不释放锁,已经进入了阻塞状态,因为object没有释放锁,子线程又拿不到锁,所以就卡死了,其实是主线程阻塞,子线程得不到锁(CPU的运行机会)。

此时的主线程仿佛在对子线程说:你咬我呀,我就是占着茅坑(锁)不拉屎(运行),子线程说,你有本事把茅坑让给我呀,主线程说,我就是不让。两者相斥不下,就卡死了。

如果注释掉join相关代码:则可以看到主线程执行完毕(一口气把锁用完,然后交出锁),才会执行子线程。

2.2、main方法对mythread(子线程)添加锁,代码顺利跑完(释放锁)

注:运行前,需要确保上述代码中的main方法中的代码同步块是mythread

synchronized (mythread)

可以看到,主线程for循环,在i=20之前,主线程和子线程是交替执行的。

i=20,mythread调用了join,貌似在说,main老兄你先歇一歇(阻塞),我运行完毕你再来运行。

看到的结果就是,直到子线程运行完毕,主线程才接着从20开始运行。

 

三、结论

最后,再回顾一下main方法中的代码sysnchronized代码。

synchronized (object)
synchronized (mythread)

失之毫厘谬以千里,仅仅是synchronized对象的不同,结果就造成这么大的差异。

此时,再回顾一下开头的结论: join()会释放Thread的锁,不会释放线程对象的锁(可能会造成死锁)。

此时,是不是豁然开朗了?

所以针对于这个问题,要看join的外层,synchronized作用的对象,是object实体对象,还是thread!

尾言

学好多线程,这些都是绕不过去的点,只能深挖后一个一个突破,加油!

1、 JAVA多线程:synchronized理论和用法 | Lock和ReentrantLock Volatile 区别和联系(一)

2、JAVA多线程:yield/join/wait/notify/notifyAll等方法的作用(二)

3、JAVA多线程:狂抓!join()方法到底会不会释放锁,给你彻底介绍清楚(三)

4、JAVA多线程:sleep(0)、sleep(1)、sleep(1000)的区别(四)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xp871038951/article/details/123023851

智能推荐

FSL 功能磁共振影像分析: single-session_fsl 头动参数加入协变量-程序员宅基地

文章目录什么是single session分析基于HRF的模型信号多元回归t contastf contrastsingle session分析是fmri实验分析的最简单情况之一,这里以FSL官方的例子为例,总结一下这个方法:http://fsl.fmrib.ox.ac.uk/fslcourse/lectures/feat1_part2.pdf什么是single session分析sing..._fsl 头动参数加入协变量

《史仙》入围凤凰网首届原创文学大赛-程序员宅基地

“凤凰网首届原创文学大赛”第二批入围作品名单公布史仙作者:易经生更新时间:2013-12-15从一位不知名的天不怕地不怕的“飞天蜈蚣”,究竟是怎么样的莫名其妙踏上修仙路.“凤凰网首届原创文学大赛”自今年10月1日公布第一批入围名单后,我们又收到了近千部的作品投稿,其中不乏让人惊喜者。此次发布的是大赛第二批入围作品。编辑们加班加点,严格筛选,力求不错过每一部好

Android笔记:调用摄像头拍照保存至指定目录_android 拍照 指定路径-程序员宅基地

Android 调用摄像头,拍照,获取原图 Intent_android 拍照 指定路径

RuoYi(若依)前后端分离版本,windows下部署_若依版本号查询-程序员宅基地

若依前后端分离版本部署:(源代码地址:https://gitee.com/y_project/RuoYi-Vue)工具:IDEA, Redis, Mysql 下载完包,解压后分开导入IDEA 就不过多介绍了,详见(http://doc.ruoyi.vip/ruoyi-vue/document/hjbs.html):这里主要介绍部署:windows + tomcat..._若依版本号查询

socket套接字的参数_socket函数第三个参数-程序员宅基地

socket 函数的第三个参数决定最终采⽤的协议。只需记住以下两种:UDP 套接字使用Ipv4 的协议族(PF_INET),和⾯向消息的数据传输(SOCK_DGRAM),对应第三个参数只能是IPPROTO_UDPint udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);TCP 套接字使用Ipv4 的协议族(PF_INET),和⾯向连接的数据传输(SOCK_STREAM),对应第三个参数只能是IPPROTO_TCPint tcp_soc_socket函数第三个参数

Android ViewTreeObserver使用总结-程序员宅基地

我们知道在oncreate中View.getWidth和View.getHeight无法获得一个view的高度和宽度,这是因为View组件布局要在onResume回调后完成。所以现在需要使用getViewTreeObserver().addOnGlobalLayoutListener()来获得宽度或者高度。这是获得一个view的宽度和高度的方法之一。OnGlobalLayoutListener..._viewtreeobserver

随便推点

Win11网络不稳定怎么办?Win11连接wifi频繁掉线的解决方法_win11远程桌面爱掉线_小鱼系统一键重装的博客-程序员宅基地

4、如果在执行【ipconfig/flushdns】命令的时候,提示无法刷新DNS解析缓存执行期间,函数出了问题,一般是本地的DNSClient服务没有正常启动导致的。Win11网络不稳定怎么办?1、首先,按键盘上的【Win+X】组合键,或右键点击任务栏上的【开始图标】,在打开的菜单项中,选择【Windows终端(管理员)】;1、首先,按键盘上的【Win+X】组合键,或右键点击任务栏上的【Windows开始图标】,打开的隐藏菜单项中,选择【计算机管理】;..._win11远程桌面爱掉线

Docker容器学习笔记二_具名挂载匿名挂载 指定目录挂载:-程序员宅基地

六、容器数据卷1.什么是容器卷?docker的理念回顾将应用和环境打包成一个镜像!数据?如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化MySQL,容器删除了,删库跑路!需求:MySQL数据可以存储在本地!容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!2.使用数据卷方式一 :直接使用命令挂载 -v-v_具名挂载匿名挂载 指定目录挂载:

python狗狗年龄换算_《python深度学习》笔记---5.2-3、猫狗分类(基本模型)-程序员宅基地

《python深度学习》笔记---5.2-3、猫狗分类(基本模型)一、总结一句话总结:模型的话也是比较普通的卷积神经网络,就是图像数据用的生成器:ImageDataGenerator1、ImageDataGenerator.flow_from_directory常用参数的意思?|||-begintrain_generator =train_datagen.flow_from_directory(t..._宠物年龄识别深度学习

让你的APP轻松加上扫描二维码功能-程序员宅基地

在这个二维码横行的年代,如果一个APP连扫描二维码的功能都没有是会被耻笑的。今天小老虎教小白们如何为自己的APP添加扫描二维码功能和生成二维码,并做到外部扫描跳转网页,内部扫描跳转具体Activity。

构建高可用可伸缩系统设计的一些方法论-程序员宅基地

本文提供一些方法论,希望这些方法论能够指导设计一个高可用的系统架构

推荐文章

热门文章

相关标签