答案
会
不过不能确切的说
Demo
网上找了很久没有找到答案,从书中找答案,《Java并发编程艺术》、《Java并发编程实战》均没有找到,在《Java多线程编程核心技术》中找到了答案,这个Demo来自这本书的268页:
package com.leesin.heightConcurrent.join;
/**
* @description: join会释放锁
* @author: Leesin.Dong
* @date: Created in 2020/3/18 22:50
* @version:
* @modified By:
*/
public class JoinReleaseLock {
public static void main(String[] args) {
ThreadB b = new ThreadB();
ThreadA a = new ThreadA(b);
a.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadC c = new ThreadC(b);
c.start();
}
static class ThreadA extends Thread {
private ThreadB b;
public ThreadA(ThreadB b) {
super();
this.b = b;
}
@Override
public void run() {
try {
synchronized (b) {
b.start();
b.join();//执行join()方法的一瞬间,b锁立即释放。
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String newString = new String();
Math.random();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadB extends Thread {
@Override
public void run() {
try {
System.out.println("b run begin timer=" + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println("b run begin timer=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void bService() {
System.out.println("打印了BService time = " + System.currentTimeMillis());
}
}
static class ThreadC extends Thread {
private ThreadB threadB;
public ThreadC(ThreadB threadB) {
super();
this.threadB = threadB;
}
@Override
public void run() {
threadB.bService();
}
}
}
书中的解释:
由于ThreadA释放了ThreadB中的锁,所以线程ThreadC可以调用ThreadB中的同步方法,synchrd public void bService()。
分析
看过Join源码的都知道,其中的核心就是
if (millis == 0) { //由于上一步传入参数为0,因此调用当前判断
while (isAlive()) { //判断子线程是否存活
wait(0); //调用wait(0)方法
}
}
即,只要子线程还活着,就一直wait,阻塞当前主线程,直到被唤醒。
即join底层还是wait(),众所周知wait方法会释放锁,所以推测join也会释放锁,不过网上有很多join不释放的说法。
object.wait()和thread.join()
join()属于Thread类中,thread的对象锁,因为thread.join()这个join里面是this这个锁,也就是thread,即在主线程中调用t.join()相当于t.wait(),我们去掉join这个方法,就相当于
main(){
t.wait();
}
所以
main(){
synchronized(obj){
thread.join(); //join不释放锁
}
}
main(){
synchronized(thread){
thread.join(); //join释放锁
}
}
一句话概括:
主线程(mian) 释放掉 子线程(thread.join中的thread)这把锁
拾遗
题外话,上面看到join是wait的封装,那么wait什么时候被唤醒呢?让主线程保持运行呢?
每个线程退出的时候会调用notofyAll()方法,通知所有等待在该线程对象上的线程。
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
* 这个方法由系统调用,当该线程完全退出前给它一个机会去释放空间。
*/
private void exit() {
if (group != null) { //线程组在Thread初始化时创建,存有创建的子线程
group.threadTerminated(this); //调用threadTerminated()方法
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
/** Notifies the group that the thread {@code t} has terminated.
* 通知线程组,t线程已经终止。
*
void threadTerminated(Thread t) {
synchronized (this) {
remove(t); //从线程组中删除此线程
if (nthreads == 0) { //当线程组中线程数为0时
notifyAll(); //唤醒所有待定中的线程
}
if (daemon && (nthreads == 0) &&
(nUnstartedThreads == 0) && (ngroups == 0))
{
destroy();
}
}
}
sleep、join、yield、wait区别?
sleep 不释放锁、释放cpu
join 释放锁、抢占cpu
yiled 不释放锁、释放cpu
wait 释放锁、释放cpu
记住一句话:cpu是非常宝贵的,所以只有running的时候才会获取CPU时间片。