juc之二:生产者与消费者

1.使用等待唤醒机制模拟生产者和消费者模式

package com.zy.juc;

/**
 * 生产者与消费者案例:
 * 等待唤醒机制
 */
public class TestProducerAndConsumerLock {

    public static void main(String[] args) {
        Clerk clerk1 = new Clerk();
        Producer producer = new Producer(clerk1);
        Consumer consumer = new Consumer(clerk1);
        new Thread(producer, "生产者A").start();
        new Thread(consumer, "消费者A").start();
        // 若是进货与卖货方法,不再循环中,即没使用while循环,而是用if进行啊判断,
        // 则当再增加一个消费者和一个生产者时,可能会出现问题了
        new Thread(producer, "生产者B").start();
        new Thread(consumer, "消费者B").start();

    }

}

/**
 * 店员
 * 同时有卖货和进货的方法
 */

class Clerk{

    // 初始货物数量统计
    private int product = 0;

    // 店员卖货的方法
    public synchronized void sale(){
        while (product <= 0) { //为了避免虚假唤醒问题,应该总是使用在while循环中,此处不能用if
            System.out.println("目前缺货中,暂时无法提供服务,请下次再来");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 消费者可以买货物
        --product;
        System.out.println(Thread.currentThread().getName() + " : " + product);
        // 通知
        this.notifyAll();
    }

    // 店员进货的方法
    public synchronized void purchase(){
        while (product >= 1) { //为了避免虚假唤醒问题,应该总是使用在while循环中,此处不能用if
            System.out.println("货品已经满仓,停止进货!");
            try{
                this.wait(); // 店员停止进货
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 生产者可以生产货物
        ++product;
        System.out.println(Thread.currentThread().getName() + " : " + product);
        // 通知卖货
        this.notifyAll();
    }

}

/**
 * 生产者
 */
class Producer implements Runnable {

    private Clerk clerk;

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

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

/**
 * 消费者
 */
class Consumer implements Runnable {

    private Clerk clerk;

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

    @Override
    public void run() {
        for (int i = 0; i < 10; i ++){
            clerk.sale();
        }
    }
}
下图即为虚假唤醒结果示例:
juc之二:生产者与消费者_第1张图片
图片.png

2.通过Lock及Condition来实现生产者消费者模型

 Condition 接口描述了可能会与锁有关联的条件变量。
        这些变量在用法上与使用 Object.wait 访问的隐式监视器类似,但提供了更强大的功能。
        需要特别指出的是,单个 Lock 可能与多个 Condition 对象关联。
        为了避免兼容性问题, Condition 方法的名称与对应的 Object 版本中的不同。
 在 Condition 对象中,
        与  wait、  notify 和 notifyAll 方法对应的分别是:
            await、 signal 和 signalAll。
 Condition 实例实质上被绑定到一个锁上。
        要为特定 Lock 实例获得Condition 实例,请使用其 newCondition() 方法。
package com.zy.juc;

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

public class TestProducerAndConsumerLock {
    public static void main(String[] args) {
        Clerk01 clerk = new Clerk01();
        Producer01 producer = new Producer01(clerk);
        Consumer01 consumer = new Consumer01(clerk);
        new Thread(producer, "生产者甲").start();
        new Thread(consumer, "消费者甲").start();
        new Thread(producer, "生产者乙").start();
        new Thread(consumer, "消费者乙").start();
    }
}

/**
 * 店员
 */
class Clerk01 {

    // 共享资源
    private int product = 0;

    // 同步锁
    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    // 进货方法
    public void purchase(){
        lock.lock();
        try{
            while (product >= 10) { //为了避免虚假唤醒问题,应该总是使用在while循环中,此处不能用if
                System.out.println("满仓了,停止进货");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            ++product;
            System.out.println(Thread.currentThread().getName() + " : " + product);
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    // 卖货方法
    public void sale(){
        lock.lock();
        try{
            while (product <= 0){ //为了避免虚假唤醒问题,应该总是使用在while循环中,此处不能用if
                System.out.println("没货了,请等待");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            --product;
            System.out.println(Thread.currentThread().getName() + " : " + product);
            condition.signalAll();
        }finally {
            lock.unlock();
        }

    }
}

/**
 * 生产者
 */
class Producer01 implements Runnable{

    private Clerk01 clerk;

    public Producer01(Clerk01 clerk){
        this.clerk = clerk;
    }

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

/**
 * 消费者
 */
class Consumer01 implements Runnable {

    private Clerk01 clerk;

    public Consumer01(Clerk01 clerk){
        this.clerk = clerk;
    }

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

3.交替打印

编写一个程序,开启 3 个线程,这三个线程的 ID 分别为
A、 B、 C,每个线程将自己的 ID 在屏幕上打印 10 遍,要
求输出的结果必须按顺序显示。
如: ABBCCCABBCCC…… 依次递归
package com.zy.juc;

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

public class TestABC {
    public static void main(String[] args) {

        PrintABC printABC = new PrintABC();

        new Thread(() -> {
            for (int i = 1; i <= 10; i ++){
                printABC.printA(i);
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i ++){
                printABC.printB(i);
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i ++){
                printABC.printC(i);
            }
        }, "C").start();
    }
}

class PrintABC {

    private int no = 1;

    private Lock lock = new ReentrantLock();

    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    // 打印A的方法
    public void printA(int count){
        lock.lock();
        try {
            // 判断是否到A
            while (no != 1){
                try {
                    condition1.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 打印A
            for (int i = 0; i < 1; i ++){
                System.out.println(Thread.currentThread().getName() + "==========" + i + "=====" + count);
            }
            // 唤醒B
            no = 2;
            condition2.signal();
        }finally {
            lock.unlock();
        }
    }

    // 打印B的方法
    public void printB(int count){
        lock.lock();
        try{
            // 判断是否到B
            while (no != 2) {
                try {
                    condition2.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 打印B
            for (int i = 0; i < 2; i ++){
                System.out.println(Thread.currentThread().getName() + "==========" + i + "=====" + count);
            }
            // 唤醒C
            no = 3;
            condition3.signal();
        }finally {
            lock.unlock();
        }
    }

    // 打印C的方法
    public void printC(int count){
        lock.lock();
        try{
            while (no != 3){
                try {
                    condition3.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 打印C
            for (int i = 0; i < 3; i ++){
                System.out.println(Thread.currentThread().getName() + "==========" + i + "=====" + count);
            }
            System.out.println(">>>>>>>>>>>>>>>第"+ count + "轮结束<<<<<<<<<<<<<<<<<<<<<");
            // 唤醒A
            no = 1;
            condition1.signal();
        } finally {
            lock.unlock();
        }
    }
}

你可能感兴趣的:(juc之二:生产者与消费者)