澳门新葡萄京官网注册Java的wait(), notify()和notifyAll()使用心得

澳门新葡萄京官网注册 ,本篇文章是对java的
wait(卡塔尔(قطر‎,notify(卡塔尔,notifyAll(State of Qatar进行了详细的解析介绍,必要的相恋的人参谋下。

wait(),notify()和notifyAll()都是java.lang.Object的方法:
wait(): Causes the current thread to wait until another thread invokes
the notify() method or the notifyAll() method for this object.
notify(): Wakes up a single thread that is waiting on this object’s
monitor.
notifyAll(): Wakes up all threads that are waiting on this object’s
monitor.

那八个点子,都是Java语言提供的贯彻线程间窒碍(BlockingState of Qatar和垄断(monopoly卡塔尔进程内调解(inter-process
communication卡塔尔(قطر‎的底层机制。在解释什么使用前,先说美素佳儿下两点:

1.
正如Java内别的对象都能形成锁(Lock卡塔尔(قطر‎雷同,任何对象也都能成为标准队列(Condition
queueState of Qatar。而以此指标里的wait(State of Qatar,
notify(卡塔尔(قطر‎和notifyAll(卡塔尔(قطر‎则是以此规范队列的原来(intrinsic卡塔尔的秘技。

2.
三个对象的固有锁和它的原本条件队列是连锁的,为了调用对象X内条件队列的法子,你必得获得对象X的锁。那是因为等待状态条件的建制和保管状态一而再性的编写制定是牢牢的结合在合营的。

(An object’s intrinsic lock and its intrinsic condition queue are
related: in order to call any of the condition queue methods on object
X, you must hold the lock on X. This is because the mechanism for
waiting for state-based conditions is necessarily tightly bound to the
mechanism fo preserving state consistency)

依照上述两点,在调用wait(),
notify(卡塔尔国或notifyAll(卡塔尔(قطر‎的时候,必须先获得锁,且状态变量须由该锁爱慕,而固有锁对象与原本条件队列对象又是同贰个对象。也正是说,要在有个别对象上奉行wait,notify,先必得锁定该目的,而相应的状态变量也是由该对象锁爱戴的。

知晓怎么利用后,大家来问下面包车型地铁难点:

  1. 实践wait, notify时,不获取锁会怎样?

请看代码:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        obj.wait();
        obj.notifyAll();
}

进行以上代码,会抛出java.lang.IllegalMonitorStateException的老大。

  1. 施行wait, notify时,不获得该目标的锁会怎么着?

请看代码:

public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Object lock = new Object();
        synchronized (lock) {
            obj.wait();
            obj.notifyAll();
        }
    }

实践代码,相符会抛出java.lang.IllegalMonitorStateException的非常。

  1. 怎么在实施wait, notify时,必需获得该指标的锁?

那是因为,如果未有锁,wait和notify有希望会产生竞态条件(Race
ConditionState of Qatar。思忖以下分娩者和消费者的光景:

1.1劳动者检查标准(如缓存满了)-> 1.2劳动者必须等待

2.1买主花费了一个单位的缓存 -> 2.二双重设置了标准(如缓存没满)
-> 2.3调用notifyAll(卡塔尔(قطر‎唤醒分娩者

大家盼望的一一是: 1.1->1.2->2.1->2.2->2.3

但在八线程景况下,顺序有相当大希望是
1.1->2.1->2.2->2.3->1.2。也等于说,在劳动者还没有wait在此以前,消费者就曾经notifyAll了,那样的话,分娩者会一直等下去。

据此,要消除那个主题素材,必须在wait和notifyAll的时候,获得该对象的锁,以有限支撑同步。

请看以下利用wait,notify实现的一个劳动者、叁个主顾和一个单位的缓存的粗略模型:

public class QueueBuffer {
    int n;
    boolean valueSet = false;
    synchronized int get() {
        if (!valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n) {
        if (valueSet)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

public class Producer implements Runnable {
    private QueueBuffer q;
    Producer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

public class Consumer implements Runnable {
    private QueueBuffer q;
    Consumer(QueueBuffer q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        QueueBuffer q = new QueueBuffer(); 
        new Producer(q); 
        new Consumer(q); 
        System.out.println("Press Control-C to stop."); 
    }
}

进而,JVM通过在施行的时候抛出IllegalMonitorStateException的老大,来确认保障wait,
notify时,获得了目的的锁,进而撤销隐形的Race Condition。

末段来看看一道题:写一个八十四线程程序,轮流输出1,2,1,2,1,2……

利用wait, notify解决:

public class OutputThread implements Runnable {
    private int num;
    private Object lock;
    public OutputThread(int num, Object lock) {
        super();
        this.num = num;
        this.lock = lock;
    }
    public void run() {
        try {
            while(true){
                synchronized(lock){
                    lock.notifyAll();
                    lock.wait();
                    System.out.println(num);
                }
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        final Object lock = new Object();
        Thread thread1 = new Thread(new OutputThread(1,lock));
        Thread thread2 = new Thread(new OutputThread(2, lock));
        thread1.start();
        thread2.start();
    }
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注