• java 虚假唤醒(SpuriousWakeups)


    public class SpuriousWakeups {

    private Object object = new Object();

    public int count = 0;

    public void get(int cnt) {
    synchronized (object) {
    if (count <= 0) {
    try {
    object.wait();
    }
    catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    count = count - cnt;
    System.out.println(Thread.currentThread() + ": final " + count);
    }
    }

    public void put(int cnt) {
    synchronized (object) {
    count = count + cnt;
    object.notify();
    }
    }


    public static void main(String[] args) throws InterruptedException {

    SpuriousWakeups spuriousWakeups = new SpuriousWakeups();

    Thread put1 = new Thread(new Runnable() {
    @Override public void run() {
    spuriousWakeups.put(1);
    }
    });

    Thread get1 = new Thread(new Runnable() {
    @Override public void run() {
    spuriousWakeups.get(1);
    }
    });

    Thread get2 = new Thread(new Runnable() {
    @Override public void run() {
    spuriousWakeups.get(1);
    }
    });
    //get2.setPriority(9);

    // get1先获取, 让object.wait 释放object的monitor
    get1.start();
    Thread.sleep(100);
    // 放入数据
    put1.start();
    get2.start();
    }
    }

    执行的结果是:
    1、
    Thread[Thread-1,5,main]: final 0
    get1获取monitor往下执行,结束后释放monitor;get2获得get1释放的monitor,其线程由BLOCKED状态转为WAITING状态
    2、
    Thread[Thread-2,5,main]: final 0
    Thread[Thread-1,5,main]: final -1
    get2抢先获得monitor执行完毕后,get1获得get2释放的monitor。至此线程全部执行完毕。

    JDK推荐的写法:
    public final void wait()
    throws InterruptedException导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。 换句话说,这个方法的行为就好像简单地执行呼叫wait(0) 。
    当前的线程必须拥有该对象的显示器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。

    像在一个参数版本中,中断和虚假唤醒是可能的,并且该方法应该始终在循环中使用:

    synchronized (obj) {
    while (<condition does not hold>)
    obj.wait();
    ... // Perform action appropriate to condition
    } 该方法只能由作为该对象的监视器的所有者的线程调用。 有关线程可以成为监视器所有者的方式的说明,请参阅notify方法。


    线程状态。 线程可以处于以下状态:
    NEW
    尚未启动的线程处于此状态。
    RUNNABLE
    在Java虚拟机中执行的线程处于此状态。
    BLOCKED
    被阻塞等待监视器锁定的线程处于此状态。
    WAITING
    正在等待另一个线程执行特定动作的线程处于此状态。
    TIMED_WAITING
    正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    TERMINATED
    已退出的线程处于此状态。

    总结:
    虚假唤醒原因:wait被notify后,线程由WAITING变成BLOCKED状态,来竞争monitor,但是另外一个线程BLOCKED也会来竞争monitor,是没法控制到底是谁先拿到monitor的。
    如果不是wait的线程先拿到monitor,那当wait的线程拿到monitor的时候,共享的值已经改变了。







  • 相关阅读:
    Java中字符串indexof() 的使用方法
    .Net Core WebApi(3)—NLog
    .Net Core WebApi(2)—Swagger
    left join 左边有数据,右边无数据
    Angular—入门环境,项目创建,导入项目
    SQLite介绍和使用
    .Net Core-类库中创建CodeFirst
    .Net Core WebApi(1)— 入门
    .Net Jpush极光推送
    Webform中的前后端分离
  • 原文地址:https://www.cnblogs.com/sleepingDogs/p/11024123.html
Copyright © 2020-2023  润新知