JUC學習之虛假喚醒

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_34560242/article/details/81136519

虛假喚醒

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Seller seller = new Seller();
        Productor productor = new Productor(seller);
        Consumer consumer = new Consumer(seller);
        new Thread(productor, "生產者A").start();
        new Thread(consumer, "消費者B").start();
        new Thread(productor, "生產者C").start();
        new Thread(consumer, "消費者D").start();
    }
}

// 銷售員
class Seller {
    private int product = 0;

    // 進貨
    public synchronized void get() {
        if (product >= 1) {
            System.out.println("貨物已滿");
            try {
                // 對應Object中的 wait()
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " : " + ++product);
        // 對應Object中的notifyAll()
        this.notifyAll();
    }

    // 銷售
    public synchronized void sale() {
        if (product <= 0) {
            System.out.println("貨物賣完");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " : " + --product);
        this.notifyAll();
    }
}

// 生產者
class Productor implements Runnable {
    private Seller seller;

    public Productor(Seller seller) {
        this.seller = seller;
    }

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

class Consumer implements Runnable {
    private Seller seller;

    public Consumer(Seller seller) {
        this.seller = seller;
    }

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

解決虛假喚醒

對於Object.wait()方法,JDK開發文檔是這樣說的

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
 }

一、使用synchronized關鍵字

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Seller seller = new Seller();
        Productor productor = new Productor(seller);
        Consumer consumer = new Consumer(seller);
        new Thread(productor, "生產者A").start();
        new Thread(consumer, "消費者B").start();
        new Thread(productor, "生產者C").start();
        new Thread(consumer, "消費者D").start();
    }
}

// 銷售員
class Seller {
    private int product = 0;

    // 進貨
    public synchronized void get() {
        while (product >= 1) {
            System.out.println("貨物已滿");
            try {
                this.wait(); // wait()方法應該總是使用在while裏面可以防止虛假喚醒
            } 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 Productor implements Runnable {
    private Seller seller;

    public Productor(Seller seller) {
        this.seller = seller;
    }

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

class Consumer implements Runnable {
    private Seller seller;

    public Consumer(Seller seller) {
        this.seller = seller;
    }

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

二、使用同步鎖

public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Seller seller = new Seller();
        Productor productor = new Productor(seller);
        Consumer consumer = new Consumer(seller);
        new Thread(productor, "生產者A").start();
        new Thread(consumer, "消費者B").start();
        new Thread(productor, "生產者C").start();
        new Thread(consumer, "消費者D").start();
    }
}

// 銷售員
class Seller {
    private int product = 0;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 進貨
    public void get() {
        lock.lock();
        try {
            while (product >= 1) {
                System.out.println("貨物已滿");
                try {
                    // 對應Object中的 wait()
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " : " + ++product);
            // 對應Object中的notifyAll()
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    // 銷售
    public synchronized 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.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

// 生產者
class Productor implements Runnable {
    private Seller seller;

    public Productor(Seller seller) {
        this.seller = seller;
    }

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

class Consumer implements Runnable {
    private Seller seller;

    public Consumer(Seller seller) {
        this.seller = seller;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            seller.sale();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章