09_并发协作

线程协作、线程通信

3个解决线程中间通信问题的方法
方法描述
final void wait()线程一直等待,直到其他线程通知,与sleep不同,会释放锁
final void wait(long timeout)指定等待的毫秒数
final void notify()唤醒一个处于等待状态的线程
final void notifyAll()唤醒同一个对象上所有调用wait方法的线程,优先级高的线程优先调度

1、生产者消费者模式

解决线程通信问题

管程法

使用容器作为缓冲区(buffer 共享内存)实现

  • 生产者:负责生产数据的模块(可能是方法、对象、线程、进程)
  • 消费者:负责处理数据的模块(可能是方法、对象、线程、进程)
  • 缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区,生产者将生产的数据放入缓冲区,消费者从缓冲区拿需要的数据
package com.tsymq.thread.concurrentcollaboration;

public class ProducerConsumer {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Producer(container).start();
        new Consumer(container).start();
    }
}

// 生产者
class Producer extends Thread{
    SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        // 生产
        for (int i = 1; i <= 200; i++) {
            System.out.println("生产第" + i + "个数据");
            container.push(new Data(i));
        }
    }
}

// 消费者
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        // 消费
        for (int i = 1; i <= 200; i++) {
            System.out.println("消费第" + container.pop().id + "个数据");
        }
    }
}

// 缓冲区
class SynContainer{
    Data[] dataBuffer = new Data[10];
    int count = 0;

    // 存储 生产
    public synchronized void push(Data data){
        // 当容器还剩余空间时才能生产
        if (count == dataBuffer.length){    // 容器已满,无法生产
            try {
                this.wait();    // 线程阻塞,等待消费者通知生产时解除阻塞
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 存在空间,可以生产
        dataBuffer[count] = data;

        // 容器里有数据了,通知消费者可以获取数据
        this.notify();

        count++;
    }

    // 获取 消费
    public synchronized Data pop(){
        // 当容器中存在数据时,才能消费
        // 若无数据只能等待
        if (count == 0){
            try {
                this.wait();    // 线程阻塞,生产者放入数据时,通知解除阻塞
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 存在数据,可以消费
        count--;

        // 容器里有空间了,通知生产者可以生产数据
        this.notify();      // this.notifyAll();
        return dataBuffer[count];
    }
}

// 数据
class Data{
    int id;
    public Data(int id) {
        this.id = id;
    }
}
信号灯法

借助标志位

package com.tsymq.thread.concurrentcollaboration;

public class SignalLight {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Audience(tv).start();
    }
}

// 生产者 演员
class Player extends Thread{
    TV tv;

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

    @Override
    public void run() {
        for (int i = 0; i < 20; i++){
            if (i%2 == 0){
                tv.play("卢本伟NB!");
            } else {
                tv.play("假猪套天下第一!");
            }
        }
    }
}

// 消费者 观众
class Audience extends Thread{
    TV tv;

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

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

// 同一个资源 电视
class TV{
    String voice;

    // 信号灯
    // T 表示演员表演,观众等待
    // F 表示观众观看,演员等待
    boolean light = true;

    // 表演
    public synchronized void play(String voice){
        // 演员等待
        if(!light){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 开始表演
        System.out.println("表演:" + voice);
        this.voice = voice;
        // 表演了一段,让观众看
        this.notify();
        // 切换信号灯
        this.light = !this.light;
    }

    // 观看
    public synchronized void watch(){
        // 观众等待
        if(light){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 开始观看
        System.out.println("听到:" + voice);
        // 看完了,通知演员继续表演
        this.notify();
        // 切换信号灯
        this.light = !this.light;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值