ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-04-13 05:00:43  阅读:204  来源: 互联网

标签:多线程 JAVA synchronized object mythread 线程 join main


原文:https://blog.csdn.net/succing/article/details/123023851

 

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

锁,这个概念比较抽象,拿到锁,就意味着拿到了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);
}
}
}
}
二、运行结果
1.main方法对object添加锁,代码卡死在20不动了,造成死锁(不释放锁)
注:运行前,需要确保上述代码中的main方法中的代码同步块是object,如下所示!

synchronized (object)


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

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

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

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


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!

标签:多线程,JAVA,synchronized,object,mythread,线程,join,main
来源: https://www.cnblogs.com/fuyuanming/p/16138469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有