Join()会不会释放锁?

join()方法在Java中实际上会释放锁。它的工作原理类似wait(),会导致当前线程等待子线程结束,期间释放持有锁,使得其他线程可以进入同步块。当子线程执行完毕,通过notifyAll()唤醒等待的线程。
摘要由CSDN通过智能技术生成

文章目录


答案

不过不能确切的说

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时间片。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值