Java多线程问题--join()的使用以及方法join()后面的代码提前运行的原因

本文深入探讨Java中线程的join方法,解释其工作原理,包括如何使当前线程阻塞直至另一个线程完成,以及与synchronized、sleep方法的区别。通过具体代码示例,分析join方法在不同场景下的行为表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文内容部分引自《Java多线程编程核心技术》,感谢作者!!!

代码地址:https://github.com/xianzhixianzhixian/thread.git

join()方法的使用

1、join()方法的用途是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。

2、join()和synchronized的区别:join()在内部使用的是wait()方法进行等待,而synchronized关键字使用的是“对象监视器”原理作为同步。join()执行后会立马释放锁,而synchronized则会持有锁直到运行结束。

3、在join的过程中,如果当前线程对象被中断,则当前线程出现java.lang.InterruptedException异常。

4、join(long)和sleep(long)的区别:join(long)的内部是由wait(long)实现的,所以join(long)争抢到锁执行后会立刻释放锁,而Thread.sleep(long)则会使线程睡眠long毫秒后执行完相应的代码后释放锁。

5、join(long)和Thread.start()在同一个代码块中时,join(long)大部分先运行。

join(long)后面的代码提前运行示例及原因

ThreadA.java

/**
 * @author: xianzhixianzhixian
 * @date: 2019-01-07 21:34
 */
public class ThreadA extends Thread {

    private ThreadB b;

    public ThreadA(ThreadB b) {
        this.b = b;
    }

    @Override
    public void run() {
        try {
            synchronized (b) {
                System.out.println("begin A ThreadName="+
                        Thread.currentThread().getName()+" "
                        +System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("end A ThreadName="+
                        Thread.currentThread().getName()+" "
                        +System.currentTimeMillis());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ThreadB.java

/**
 * @author: xianzhixianzhixian
 * @date: 2019-01-07 21:34
 */
public class ThreadB extends Thread {
    @Override
    synchronized public void run() {
        try {
            System.out.println("begin B ThreadName="+
                    Thread.currentThread().getName()+" "
                    +System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("end B ThreadName="+
                    Thread.currentThread().getName()+" "
                    +System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Run.java

/**
 * 方法join()后面的代码提前运行示例(有时会出现这种情况)
 * 这里涉及到join(long)和a、b线程争抢对象锁的问题
 * @author: xianzhixianzhixian
 * @date: 2019-01-07 21:38
 */
public class Run {
    public static void main(String[] args) {
        try {
            ThreadB b = new ThreadB();
            ThreadA a = new ThreadA(b);
            a.start();
            b.start();
            b.join(2000);
            System.out.println("main end "+System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行结果:

第一种情况:A线程运行完之后main中的语句执行完毕,B线程继续执行完毕

原因:

1、 b.join(2000)方法先抢到B锁, 然后将B锁进行释放;

2、ThreadA抢到锁,打印ThreadAbegin并且sleep(5000);

3、ThreadA打印ThreadA end, 并释放锁;

4、这时join(2000)和Tl订eadB争抢锁, 而join(2000)再次抢到锁, 发现时间已过, 释放锁后打印main end;

5、ThreadB抢到锁打印ThreadB begin;

6、5秒之后再打印ThreadBend。

第二种情况:A线程运行完之后,B线程继续执行完毕,main中的语句执行完毕

原因:

1、b.join(2000)方法先抢到B锁, 然后将B锁进行释放;

2、T比eadA抢到锁,打印TeadAbegin并且sleep(5000);

3、ThreadA打印T缸eadAend, 并释放锁;

4、这时join(2000)和ThreadB争抢锁,而ThreadB抢到锁后执行sleep(5000)后释放锁;

5、main end在最后输出。

第三种情况:实验不出来,截书上图吧

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值