java学习笔记之多线程生产者与消费者
来源:互联网 发布:网络创业课理论与实践 编辑:程序博客网 时间:2024/06/05 01:15
生产者-消费者问题是一个经典的线程同步问题。可以理解为:生产者生产出一个产品,将其放入缓冲区,消费者从缓冲区取走产品之后,生产者继续生产产品。注意的是,生产者必须等待消费者取走产品之后才继续生产,消费者也必须在缓冲区有产品是才消费。
一、首先,最简单的模型就是单生产者,单消费者,单次生产消费
public class Resource {private String name;private boolean flag;private int count=1;public void setResource(String name){this.name = name + "---" +count;count++;System.out.println(Thread.currentThread().getName()+"生产者"+this.name);}public void getResource(){System.out.println(Thread.currentThread().getName()+"消费者"+this.name);}}public class Producer implements Runnable {private Resource rec; //这一步是为了保证生产者和消费者操作的资源是一样的public Producer(Resource rec){this.rec=rec;}public void run(){ rec.setResource("面包");}}public class Customer implements Runnable{private Resource res;Customer(Resource res){this.res=res;}public void run(){ res.getResource();}}public class ProducerCustomer {public static void main(String[] args) {Resource res = new Resource();Producer pro = new Producer(res);Customer cus = new Customer(res);Thread th1 = new Thread(pro);Thread th2 = new Thread(cus);th1.start();th2.start();}}
结果是:
Thread-0生产者面包---1
Thread-1消费者面包---1
意思就是生产者生产一个产品,消费者就消费一个产品
二、单生产者单消费者多次生产消费
那么该如何实现多生产者多消费者呢?可以在生产者和消费者的run函数里面加上while(true)的判断,但是这样就会产生消费者重复消费或者生产者重复生产的问题,如下图。原因就是多线程的不安全性,那么就可以用同步来解决该问题。
当时当给生产者和消费者加上同步之后,publicsynchronizedvoid setResource(String name);publicsynchronized void getResource(),会发现又产生了生产者持续多生产和消费者持续多消费的问题,如下图
该问题是由于生产者或消费者不断拿到锁,可以不断生产或消费。那么可以在拿到锁之后,加上判断的一步,如果没有产品才生产,有产品才消费。这就可以引入等待唤醒机制。
wait():该方法可以让线程处于冻结状态,并将线程先临时存储到线程池
notify():唤醒指定线程池中的任意一个线程
notifyAll(): 唤醒指定线程池中的所有线程
注意:1)这些方法必须用在同步中,因为它们是同来操作同步锁上的线程状态的。
2)在使用这些方法时,必须标识它们所属于的锁,标识的方式就是:锁对象.wait()/锁对象.notify/锁对象.notifyAll,相同锁的notify()可以获取相同锁的wait()。(wait方法等在API中查看的时候,它是属于object的方法的)
完整程序如下:
public class Resource {private String name;private boolean flag;private int count=1;public synchronized void setResource(String name){if(flag){try{wait(); //查阅API可以知道,wait方法需要抛出InterruptedException异常,在该段代码中,wait方法对应的锁是默认的this,可以不写}catch(InterruptedException e){}}this.name = name + "---" +count;count++;System.out.println(Thread.currentThread().getName()+"生产者"+this.name);flag = true;notify();}public synchronized void getResource(){if(!flag){ //在生产者或消费者拿到锁之后进行判断,是否是继续生产消费还是进入等待状态。try{wait();}catch(InterruptedException e){}} System.out.println(Thread.currentThread().getName()+"消费者"+this.name);flag=false;notify();}}public class Producer implements Runnable {private Resource rec;public Producer(Resource rec){this.rec=rec;}public void run(){while(true) rec.setResource("面包");}}public class Customer implements Runnable{private Resource res;Customer(Resource res){this.res=res;}public void run(){while(true) res.getResource();}}public class ProducerCustomer {public static void main(String[] args) {Resource res = new Resource();Producer pro = new Producer(res);Customer cus = new Customer(res);Thread th1 = new Thread(pro);Thread th2 = new Thread(cus);th1.start();th2.start();}}
三、多生产者多消费者多次生产消费
首先,肯定是要开启多个线程来产生多个生产者和多个消费者,这样有可能会产生被唤醒的线程没有再次判断标记就开始工作,导致重复生产和重复消费的问题。所以可以把if 判断改为while判断,同时在上述代码中的notify()要改成notifyAll(),如果不改的话,会出现程序在运行过程中,所有线程都处于冻结状态,也就是死锁。(如何理解--->本方线程在唤醒时,又一次唤醒了本方线程。而本方线程循环判断标记时,又一次继续等待,导致所有线程都处于冻结状态)
完整代码如下:
public class Resource {private String name;private boolean flag;private int count=1;public synchronized void setResource(String name){while(flag){ //循环判标记try{wait();//wait()方法}catch(InterruptedException e){}}this.name = name + "---" +count;count++;System.out.println(Thread.currentThread().getName()+"生产者"+this.name);flag = true;notifyAll();}public synchronized void getResource(){while(!flag){try{wait();}catch(InterruptedException e){}} System.out.println(Thread.currentThread().getName()+"消费者"+this.name);flag=false;notifyAll();}}public class Producer implements Runnable {private Resource rec;public Producer(Resource rec){this.rec=rec;}public void run(){while(true) rec.setResource("面包");}}public class Customer implements Runnable{private Resource res;Customer(Resource res){this.res=res;}public void run(){while(true) res.getResource();}}public class ProducerCustomer {public static void main(String[] args) {Resource res = new Resource();Producer pro = new Producer(res);Customer cus = new Customer(res);Thread th0 = new Thread(pro); //开启多个线程Thread th1 = new Thread(pro);Thread th2 = new Thread(cus);Thread th3 = new Thread(cus);th0.start();th1.start();th2.start();th3.start();}}
结果是
- java学习笔记之多线程生产者与消费者
- java之多线程实例 生产者与消费者
- Java回炉之多线程(二)生产者与消费者
- java 多线程学习之多生产者多消费者产生的线程安全问题分析与解决:Lock和Condition
- java线程 生产者与消费者
- java线程 生产者与消费者
- ·多线程学习笔记(五)之多生产者多消费者中的线程问题
- Java SE学习笔记:线程通信、生产者与消费者案例、线程状态(线程的生命周期)、线程操作、Condition类
- 学习和理解JAVA线程同步--生产者与消费者例子
- 学习和理解JAVA线程同步--生产者与消费者例子
- 多线程之多消费者与生产者
- 线程同步学习笔记(生产者消费者)
- 线程学习笔记(十三)-模拟生产者消费者
- java线程模拟生产者与消费者
- 生产者与消费者 java经典线程法
- JAVA线程(生产者与消费者)
- JAVA 线程间通信 - 生产者与消费者
- java线程经典之生产者与消费者
- 存储协议,你知道多少?
- H5 的复制操作
- 剑指Offer——记中国银行体检之旅
- Book4-Unit3
- H5 data-* 属性,设置获取方法总结
- java学习笔记之多线程生产者与消费者
- [Android Studio1.5][NDK r13b]Execution failed for task ':app:compileDebugNdk'. Error Code:2
- android:clipToPadding使用
- Swift初体验-泛型
- C#初级
- Book4-Unit4
- 设有一头小母牛,从出生第四年起每年生一头小母牛,按此规律,第N年时有几头母牛?
- 按钮动效
- Maven依赖Scope标签简介