Java 多线程开发 06 —— 管程法、信号灯法

系列文章目录

Java 多线程开发 01 —— 线程创建
Java 多线程开发 02 —— 静态代理模式
Java 多线程开发 03 —— Lambda表达式
Java 多线程开发 04 —— 线程状态控制、优先级、守护线程
Java 多线程开发 05 —— synchronized、Lock、死锁
Java 多线程开发 06 —— 管程法、信号灯法



生产者、消费者问题

应用场景:

  1. 假设仓库只能放一件产品,生产者放入一件产品到仓库,消费者从仓取出一件产品。
  2. 若仓库有一件产品,则生产者必须等待消费者取出一件。
  3. 若仓库没有产品,则消费者必须等待生产者放入一件产品。

这里就涉及到一个线程通信的问题。

  1. 对于生产者,在生产了一件产品后要通知消费者取走。
  2. 对于消费者,在取走了一件产品后要通知生产者生产。

在这个问题中,仅用synchronized是不够的,它不能实现不同线程之间的消息传递。

Java 提供了几个方法来解决线程之间的通信问题:

方法名 作用
wait() 表示线程一直等待,直到有其他线程通知(与sleep()不同,可以释放锁)
wait(long timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级高的优先调度

注意:这些都是Object类的方法,只能在同步方法或同步代码块中使用,否则会抛出异常。

管程法

生产者将生产好的数据放入缓冲区,消费者冲缓冲区中拿出数据,缓冲区同一时刻只能被一个人操作。

package lessen08_Thread;

//测试生产者消费者模型 —— 管程法(利用缓冲区)
public class TestPC01 {
    
    
    public static void main(String[] args) {
    
    
        Buffer buffer = new Buffer();
        new Thread(new Producer(buffer)).start();
        new Thread(new Consumer(buffer)).start();
    }
}

//生产者
class Producer implements Runnable{
    
    
    Buffer buffer = null;

    public Producer(Buffer buffer) {
    
    
        this.buffer = buffer;
    }

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            buffer.push(new Product(i));
            System.out.println("生产——>"+i);
        }
    }
}

//消费者
class Consumer implements Runnable{
    
    
    Buffer buffer = null;

    public Consumer(Buffer buffer) {
    
    
        this.buffer = buffer;
    }

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            System.out.println("消费——>"+buffer.pop().getId());
        }
    }
}

//产品
class Product{
    
    
    private int id;

    public Product(int id) {
    
    
        this.id = id;
    }

    public int getId() {
    
    
        return id;
    }
}

//缓冲区
class Buffer{
    
    
    private Product[] products = new Product[10];//存放产品
    private int count = 0;//当前缓冲区产品数量
    //放入产品[对缓冲区的操作涉及并发操作,可同步方法、同步代码块、lock]
    public synchronized void push(Product product){
    
    
        //若缓冲区满,则生产者需要等待取走
        if (count >= products.length){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        products[count++] = product;//生产
        //此时生产者生产了产品,通知消费者消费
        this.notifyAll();
    }

    //取走产品
    public synchronized Product pop() {
    
    
        //若缓冲区空,则消费者需等待生产者生产
        if(count <= 0){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        Product product = products[--count];//消费
        //此时消费者已经消费了一个产品,通知生产者生产
        this.notifyAll();
        return product;
    }
}

部分结果:

生产——>99
消费——>96
消费——>99
消费——>98
消费——>97
消费——>95
消费——>94
消费——>93
消费——>92

信号灯法

通过标志位来判断是产者、消费者是等待还执行。

package lessen08_Thread;

//测试生产者消费者模型 ———— 信号灯法(利用标志位)
public class TestPC02 {
    
    
    public static void main(String[] args) {
    
    
        TV tv = new TV();
        new Thread(new Watcher(tv)).start();
        new Thread(new Player(tv)).start();
    }
}

//生产者————演员
class Player implements Runnable{
    
    

    TV tv = null;

    public Player(TV tv) {
    
    
        this.tv = tv;
    }

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            tv.play("节目:"+i);
        }
    }
}

//消费者————观众
class Watcher implements Runnable{
    
    
    TV tv = null;

    public Watcher(TV tv) {
    
    
        this.tv = tv;
    }

    @Override
    public void run() {
    
    
        for (int i = 0; i < 100; i++) {
    
    
            tv.watch();
        }
    }
}

//产品————节目
class TV{
    
    
    String program;//表演的节目
    //true 演员表演,观众等待
    //false 观众观看,演员等待
    boolean flag = true;

    //表演
    public synchronized void play(String program){
    
    
        if (!flag){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        System.out.print("演员表演了:"+program);
        //演员表演好了,通知观众观看
        this.notifyAll();
        this.program = program;
        this.flag = false;//标志位反转

    }

    //观看
    public synchronized void watch(){
    
    
        if(flag){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        System.out.print("观众观看了:"+program);
        //观众看完了,通知演员表演
        this.notifyAll();
        this.flag = true;
    }
}

部分结果:

演员表演了:节目:0
观众观看了:节目:0
演员表演了:节目:1
观众观看了:节目:1
演员表演了:节目:2
观众观看了:节目:2

猜你喜欢

转载自blog.csdn.net/qq_39763246/article/details/113009256