线程中的join、wait、sleep的区别

一、join方法

先来看看join的三个重载方法:

final synchronized void join(long millis, int nanos) throws InterruptedException

final synchronized void join(long millis) throws InterruptedException

final synchronized void join() throws InterruptedException

这三个方法都可以

抛出 InterruptedException 异常join在内部调用wait()方法进行等待,而synchronized关键字使用的是"对象监视器"原理作为同步,

join的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行

join方法最后调用的还是 join(long millis) join()方法中调用的是join(0),当参数是0的时候表示无限期等待

来看看join(long millis)

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            //判断线程是否存活,isAlive native方法
            while (isAlive()) {
                wait(0);   //调用wait方法
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

join与异常

在join()过程中,如果当前线程被中断,则当前线程出现异常。(注意是调用thread.join()的线程被中断才会进入异常,比如a线程调用b.join(),a中断会报异常而b中断不会异常)

public class JoinThread extends Thread {
        
        public static void main(String[] args) throws InterruptedException {

            final Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("threadA run");
                    while (true) {

                    }
                }
            }, "threadA");

            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("threadB run");
                    threadA.start();
                    try {
                        threadA.join();
                    } catch (InterruptedException e) {
                        System.out.println("join error ,threadName - > "+Thread.currentThread().getName()+ e);
                    }
                }
            }, "threadB");
            threadB.start();

            // 向threadB发出中断信号
            Thread.sleep(1 * 1000);
            threadB.interrupt();
        }
    }

结果如下:

B发生异常,而A并没有。

二、wait方法

属于Object类中,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。

wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常。

wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

为什么wait和notify要加锁?

调用wait方法,首先获取监视器锁,获取成功后,会让线程进入等待状态进入等待队列并释放锁,然后当其他线程调用notify或者notifyAll的时候,会选择从等待队列中选择一个线程而执行完notify后,并不会立马唤醒,原因当前线程仍然持有这把锁,处于等待状态的线程无法获取锁。

三、sleep方法

sleep 方法是属于 Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程。

让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断。

sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会

猜你喜欢

转载自blog.csdn.net/weixin_39082432/article/details/114260501