首页 科技正文

环球ug官方注册:Java 多线程基础(六)线程守候与叫醒

admin 科技 2020-06-18 37 0

 Java 多线程基础(六)线程守候与叫醒

遇到这样一个场景,当某线程内里的逻辑需要守候异步处理效果返回后才气继续执行。或者说想要把一个异步的操作封装成一个同步的历程。这里就用到了线程守候叫醒机制。

wait()、notify()、notifyAll() 等方式先容

在 Object 中,界说了 wait()、notify() 和 notifyAll() 等接口。wait() 的作用是让当前线程进入守候状态,同时,wait() 也会让当前线程释放它所持有的锁。而 notify() 和 notifyAll() 的作用,则是叫醒当前工具上的守候线程;notify() 是叫醒单个线程,而 notifyAll() 是叫醒所有的线程。

Object类中关于守候/叫醒的API详细信息如下:

notify()                                       -- 叫醒在此工具监视器上守候的单个线程。
notifyAll()                                  -- 叫醒在此工具监视器上守候的所有线程。
wait()                                         -- 让当前线程处于“守候(壅闭)状态”,“直到其他线程挪用此工具的 notify() 方式或 notifyAll() 方式”,当前线程被叫醒(进入“停当状态”)。
wait(long timeout)                    -- 让当前线程处于“守候(壅闭)状态”,“直到其他线程挪用此工具的 notify() 方式或 notifyAll() 方式,或者跨越指定的时间量”,当前线程被叫醒(进入“停当状态”)。
wait(long timeout, int nanos)  -- 让当前线程处于“守候(壅闭)状态”,“直到其他线程挪用此工具的 notify() 方式或 notifyAll() 方式,或者其他某个线程中止当前线程,或者已跨越某个现实时间量”,当前线程被叫醒(进入“停当状态”)。

二、wait() 和 notify() 示例

public class Demo02 {
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");
        synchronized (t1) {
            try {
                // 启动“线程t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();
                // 主线程守候t1通过notify()叫醒。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();
                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        synchronized (this) {
            try {
                System.out.println(Thread.currentThread().getName()+" call notify()");
                notify(); // 叫醒当前的Demo02线程
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
}
// 运行效果
main start t1
main wait()
t1 call notify()
main continue

说明:

①、 注重,图中"主线程" 代表“主线程main”。"线程t1" 代表Demo02中启动的“线程t1”。 而“锁” 代表“t1这个工具的同步锁”。
②、“主线程”通过 new ThreadA("t1") 新建“线程t1”。随后通过synchronized(t1)获取“t1工具的同步锁”。然后挪用t1.start()启动“线程t1”。
③、“主线程”执行t1.wait() 释放“t1工具的锁”而且进入“守候(壅闭)状态”。守候t1工具上的线程通过notify() 或 notifyAll()将其叫醒。
④、“线程t1”运行之后,通过synchronized(this)获取“当前工具的锁”;接着挪用notify()叫醒“当前工具上的守候线程”,也就是叫醒“主线程”。
⑤、“线程t1”运行完毕之后,释放“当前工具的锁”。紧接着,“主线程”获取“t1工具的锁”,然后接着运行。

详细历程图解

三、wait(long timeout) 和 notify()

public class Demo02 {
    public static void main(String[] args) {
        Thread t1 = new MyThread("t1");

        synchronized(t1) {
            try {
                // 启动线程t1
                System.out.println(Thread.currentThread().getName() + " start t1");
                t1.start();

                // 主线程守候t1通过notify()叫醒 或 notifyAll()叫醒,或跨越3s延时;然后才被叫醒。
                System.out.println(Thread.currentThread().getName() + " call wait ");
                t1.wait(3000);

                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
}
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    public void run() {
        System.out.println(Thread.currentThread().getName() + " run ");
        // 死循环,不停运行。
        while(true)
            ;
    }
}
// 运行效果
main start t1
main call wait 
t1 run             // 3秒后输出 main continue
main continue 

 说明:

如下图,说明晰“主线程”和“线程t1”的流程。
①、注重,图中"主线程" 代表线程main。"线程t1" 代表MyThread中启动的线程t1。 而“锁” 代表“t1这个工具的同步锁”。
②、主线程main执行t1.start()启动“线程t1”。
③、主线程main执行t1.wait(3000),此时,主线程进入“壅闭状态”。需要“用于t1工具锁的线程通过notify() 或者 notifyAll()将其叫醒” 或者 “超时3000ms之后”,主线程main才进入到“停当状态”,然后才可以运行。
④、“线程t1”运行之后,进入了死循环,一直不停的运行。
⑤、超时3000ms之后,主线程main会进入到“停当状态”,然后接着进入“运行状态”。

 详细历程图解:

四、wait() 和 notifyAll()

public class Demo02 {
    private static Object obj = new Object();
    public static void main(String[] args) {
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        MyThread t3 = new MyThread("t3");
        t1.start();
        t2.start();
        t3.start();
        try {
            System.out.println(Thread.currentThread().getName()+" sleep(5000)");
            Thread.sleep(5000); // 休眠5秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (obj) {
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
        
    }
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            synchronized (obj) { 
                try {
                    System.out.println(Thread.currentThread().getName() + " run ");
                    obj.wait();
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
// 运行效果
t1 run 
t2 run 
main sleep(5000)
t3 run 
main notifyAll()
t3 continue
t2 continue
t1 continue

说明:

①、 主线程中新建而且启动了3个线程"t1", "t2"和"t3"。
②、主线程通过sleep(5000)休眠5秒。在主线程休眠3秒的历程中,我们假设"t1", "t2"和"t3"这3个线程都运行了。以"t1"为例,当它运行的时刻,它会执行obj.wait()守候其它线程通过notify()或nofityAll()来叫醒它;相同的原理,"t2"和"t3"也会守候其它线程通过nofity()或nofityAll()来叫醒它们。
③、主线程休眠3秒之后,接着运行。执行 obj.notifyAll() 叫醒obj上的守候线程,即叫醒"t1", "t2"和"t3"这3个线程。 紧接着,主线程的synchronized(obj)运行完毕之后,主线程释放“obj锁”。这样,"t1", "t2"和"t3"就可以获取“obj锁”而继续运行了!

详细历程图解

五、 为什么notify(), wait()等函数界说在Object中,而不是Thread中

Object中的wait(), notify()等函数,和synchronized一样,会对“工具的同步锁”举行操作。

wait()会使“当前线程”守候,由于线程进入守候状态,以是线程应该释放它锁持有的“同步锁”,否则其它线程获取不到该“同步锁”而无法运行!
OK,线程挪用wait()之后,会释放它锁持有的“同步锁”;而且,凭据前面的先容,我们知道:守候线程可以被notify()或notifyAll()叫醒。现在,请思索一个问题:notify()是依据什么叫醒守候线程的?或者说,wait()守候线程和notify()之间是通过什么关联起来的?谜底是:依据“工具的同步锁”。

卖力叫醒守候线程的谁人线程(我们称为“叫醒线程”),它只有在获取“该工具的同步锁”(这里的同步锁必须和守候线程的同步锁是同一个),而且挪用notify()或notifyAll()方式之后,才气叫醒守候线程。虽然,守候线程被叫醒;然则,它不能马上执行,由于叫醒线程还持有“该工具的同步锁”。必须等到叫醒线程释放了“工具的同步锁”之后,守候线程才气获取到“工具的同步锁”进而继续运行。

总之,notify(), wait()依赖于“同步锁”,而“同步锁”是工具锁持有,而且每个工具有且仅有一个!这就是为什么notify(), wait()等函数界说在Object类,而不是Thread类中的缘故原由。

,

联博API接口

www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。

版权声明

本文仅代表作者观点,
不代表本站申博官网的立场。
本文系作者授权发表,未经许可,不得转载。

评论