三等待与唤醒

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了三等待与唤醒相关的知识,希望对你有一定的参考价值。

在Object.java中,定义了wait(), notify()和notifyAll()等接口。

notify()        -- 唤醒在此对象监视器上等待的单个线程。
notifyAll()   -- 唤醒在此对象监视器上等待的所有线程。
wait()                                         -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout)                    -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout, int nanos)  -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。

注意:1.wait()和notify()必须在synchronized块里面使用

2.调用wait()和notify()的对象必须与synchronized块锁对象一致。

 

wait()的作用是让当前线程进入等待状态,同时,wait()也会让出当前线程释放它所持有的锁。而 notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有 的线程。

 

public class WaitTest {
    
    public static void main(String[] args) {
        final Atest a = new Atest();
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                a.m1();
            }
        };
        /**
         * 经测试调用wait()方法当前线程会处于等待状态,而且会释放它所持有的锁。
         */
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        t1.start();
        try {
            /**
             * 当t1线程执行完,主线程才能继续执行。
             * 如果t1处于等待状态,主线程也无法往下执行,因为t1只是处于等待状态,而未执行完。
             */
            t1.join();    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }
    
}

class Atest{
    boolean flag = true;
    public synchronized void m1(){
        System.out.println("m1方法开始"+Thread.currentThread());
        while(flag){
            try {
                this.wait(10000);
//                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = false;
        }
        System.out.println("m1方法结束"+Thread.currentThread());
    }
}

 

这里说一下Thread类的join()方法:

join() 的作用:让“主线程”等待“该线程”结束之后才能继续运行,这里说的主线程是相对于该线程而言的,并不是指定main线程。

 

package com.fla.thread;

public class NotifyTest {
    public static void main(String[] args) {
        final Ntest n = new Ntest();
        Runnable run1 = new Runnable(){
            @Override
            public void run() {
                n.m1();
            }
        };
        Thread t1 = new Thread(run1);
        Thread t2 = new Thread(run1);
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                n.m2();
            }
        });
        t1.start();
        t2.start();
        t3.start();
    }
}

class Ntest {
    boolean flag = true ;
    public synchronized void m1(){
        System.out.println("m1方法开始"+Thread.currentThread()+",锁对象hashcode:");
        while(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("m1方法结束"+Thread.currentThread()+",锁对象hashcode:");
    }
    
    public synchronized void m2(){
        System.out.println("m2方法开始"+Thread.currentThread()+",锁对象hashcode:");
//        this.notifyAll();
        this.notify();
        flag = false ;
    }
}

 

notify()是唤醒在此对象(与同步块锁对象一致)监视器上等待的单个线程。,而notifyAll()是唤醒在此对象监视器上等待的所有线程。

wait() 和 sleep()的差别:

wait() 让当前线程处于“等待(阻塞)状态”,也会让出当前线程释放它所持有的锁,不占cpu资源。

sleep()  让线程睡眠一段时间,占着cpu进入睡眠,如果在同步代码块里面,也不会释放所持有的锁

 

这里顺便说一下Thread类的yield()方法。

yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让 其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是 当前线程又进入到“运行状态”继续运行!

以上是关于三等待与唤醒的主要内容,如果未能解决你的问题,请参考以下文章

Java线程的等待与唤醒

Java多线程:阻塞队列与等待唤醒机制初探

阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第4节 等待唤醒机制_8_等待唤醒机制代码实现_包子类&包子铺类

等待与唤醒

为啥“等待谓词”解决了条件变量的“丢失唤醒”?

JUC-三种等待唤醒方式