java多線程 生產者消費者案例-虛假喚醒


package com.java.juc;

public class TestProductAndConsumer {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Produce produce = new Produce(clerk);
        Consumer consumer = new Consumer(clerk);
        new Thread(produce, "線程A").start();
        new Thread(consumer, "線程B").start();
        new Thread(produce, "線程AA").start();
        new Thread(consumer, "線程BB").start();
    }

}

// 店員
class Clerk {
    private int product = 0;

    public synchronized void get() {
        while (product >= 1) {  //這里使用while 不使用if 防止虛假喚醒
            System.out.println("產品已滿!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " : " + ++product);
        this.notifyAll();
    }

    public synchronized void sale() {
        while (product <= 0) {
            System.out.println("缺貨!");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " : " + --product);
        this.notifyAll();
    }
}

// 生產者
class Produce implements Runnable {
    private Clerk clerk;

    public Produce(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

// 消費者
class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

 

  • public final void wait()
                    throws InterruptedException
    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

    As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

         synchronized (obj) {
             while (<condition does not hold>)  //為了防止虛假喚醒應該總是使用在循環中
                 obj.wait();
             ... // Perform action appropriate to condition
         }
     
    This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

可以使用 Lock 及 Condition 改寫上述代碼

package com.java.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestProductAndConsumer {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Produce produce = new Produce(clerk);
        Consumer consumer = new Consumer(clerk);
        new Thread(produce, "線程A").start();
        new Thread(consumer, "線程B").start();
        new Thread(produce, "線程AA").start();
        new Thread(consumer, "線程BB").start();
    }

}

// 店員
class Clerk {
    private int product = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void get() {
        lock.lock();
        try {
            while (product >= 1) {  //這里使用while 不使用if 防止虛假喚醒
                System.out.println("產品已滿!");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " : " + ++product);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public void sale() {
        lock.lock();
        try {
            while (product <= 0) {
                System.out.println("缺貨!");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " : " + --product);
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

// 生產者
class Produce implements Runnable {
    private Clerk clerk;

    public Produce(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.get();
        }
    }
}

// 消費者
class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM