Java------多线程_并发与协作_生产者消费者模式_管程法_指示灯法(十二)

Java------多线程_并发与协作_生产者消费者模式(十二)
线程与线程之间如何通讯?
使用消息队列进行通讯。
线程通信:
应用场景:生产者和消费者问题
生产者和消费者共享同一个资源,并且生产者和消费者之间互相依赖,互为条件。
1.对于生产者,没有生产产品之前,要通知消费者等待,而生产了产品之后,又需要马上通知消费者消费
2.对于消费者,在消费之后,要通知生产者已经消费结束,需要继续生产新产品以供消费
3.生产者消费者问题中,仅有synchronized是不够的
(1)synchronized可阻止并发更新同一个共享资源,实现了同步
(2)synchronized不能用来实现不同线程之前的消息传递(通信)
解决方式1:并发协作模型“生产者/消费者模式”-》管程法
1.生产者:负责生产数据的模块
2.消费者:负责处理数据的模块
3.缓冲区:消费者不能直接使用生产者的数据,它们之间有个“缓冲区”
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿要处理的数据。
优点:生产者与消费者解耦,提高效率,利用管道
buffer(共享内存)
解决方式2:并发协作模型“生产者/消费者模式”-》信号灯法
Java提供三个方法解决线程之间的通信
1.final void wait() 、 作用:表示导致当前线程一直等待,直到其他线程通知notify、或者notifyAll,与sleep不同,会释放锁。
2.final void wait(long timeout)、作用:指定等待的毫秒数
3.final void notify() 、 作用:唤醒一个处于等待状态的线程
4.final void notifyAll() 、 作用:唤醒一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度。
以上方法都是java.lang.Object类的方法都只能在同步方法或者同步代码块中使用,否则会抛出异常。

管程法:
生产者和消费者都是多线程,缓冲区采用容器(存数据、取数据)、数据。
共四种角色。
容器存:当容器没有空间了,通知消费者等待
容器取:当容器空了,通知消费者生产
管程法案例代码:【运行代码时,存在一个问题,在存储数据过程中,会爆数组越界,把异常打印注释掉后,程序可以正常运行】
一边存数据,一边去数据,当缓冲区数据为空时,消费者wait,当缓冲区数据满时,生产者wait。

package cooperation;

/**
 * 协作模型:生产者消费者实现方式一:管程法
 * 借助缓冲区
 */
public class CoTest {
    
    
    public static void main(String[] args) {
    
    
        SynContainer synContainer = new SynContainer();
        new Productor(synContainer).start();
        new Consumer(synContainer).start();
    }
}
//生产者
class Productor extends Thread{
    
    
    SynContainer container;
    //构造方法
    public Productor(SynContainer container){
    
    
        this.container = container;
    }
    @Override
    public void run() {
    
    
        //生产
        for (int i=0;i<10;i++){
    
    
            System.out.println("生产第---"+i+"个元素");
            container.push(new MDate(i));
        }
    }

}
//消费者
class Consumer extends Thread{
    
    
    SynContainer container;
    //构造方法
    public Consumer(SynContainer container){
    
    
        this.container = container;
    }
    //消费
    @Override
    public void run() {
    
    
        for (int i=0;i<1000;i++){
    
    
            System.out.println("消费第----"+container.get().id+"个元素");
        }
    }
}
//缓冲区
class SynContainer{
    
    
    //存储容器
    MDate[] mDates = new MDate[10];
    //计数器
    int count = 0;
    //存
    public synchronized void push(MDate mDate){
    
    
        //何时能生产,容器存在空间,可以生产
        //不能生产
        if (count == mDates.length){
    
    
            try {
    
    
                this.wait();  //线程阻塞,消费者通知生产者生产
            } catch (InterruptedException e) {
    
    
//                e.printStackTrace();不注释会报错
            }
        }
        mDates[count] = mDate;
        count++;
        this.notifyAll();//存在空间,通知消费者开始生产
    }
    //取
    public synchronized MDate get(){
    
    
        //何时消费
        if (count == 0){
    
    
            try {
    
    
                this.wait(); //此时线程阻塞,生产者通知消费解除阻塞
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        count--;
        MDate mDate = mDates[count];
        this.notifyAll();//存在空间唤醒生产者生产
        return mDate;
    }

}
//数据
class MDate{
    
    
    //编号
    int id;
    public MDate(int id){
    
    
        this.id = id;
    }

}

信号灯法:红灯停、绿灯行,通过真假标识。
演员表演什么,观众才能听到什么

package cooperation;

/**
 * 协作模型:生产者消费者实现方式一:信号灯法
 * 借助标志位
 */
public class CoTest01 {
    
    
    public static void main(String[] args) {
    
    
        Tv Tv = new Tv();
        new Player(Tv).start();
        new Watcher(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){
    
    
                this.tv.play("奇葩说");
            }else {
    
    
                this.tv.play("火星情报局");
            }
        }
    }

}
//消费者  观众
class Watcher extends Thread{
    
    
    Tv tv;
    //构造方法
    public Watcher(Tv tv){
    
    
        this.tv = tv;
    }
    //消费
    @Override
    public void run() {
    
    
        for (int i=0;i<20;i++){
    
    
            this.tv.watch();
        }
    }
}
//同一个资源电视
class Tv{
    
    
    String voice;
    //信号灯
    //true  表示演员表演,观众等待
    //false 表示观众观看,演员等待
    boolean flag = true;
    //表演
    public synchronized void play(String voice){
    
    
        //演员等待
        if (!flag){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        System.out.println("表演了:"+voice);
        this.voice = voice;
        this.notifyAll();
        this.flag = !this.flag;
    }
    //观看
    public synchronized void watch() {
    
    
        //观众等待
        if (flag){
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        System.out.println("听到了:"+voice);
        this.notifyAll();
        this.flag = !this.flag;
    }
}

Guess you like

Origin blog.csdn.net/cz_chen_zhuo/article/details/121700458