Java-线程(生产者消费者模式)

来源:互联网 发布:刺客信条黑旗优化差 编辑:程序博客网 时间:2024/05/22 14:14

普通的生产者消费者模式:

package ss;/** * 线程通讯实例: *  * 生产者消费者模式 *  *///产品类class Product{    String name;//名字    double price;//价格    boolean flag=false;//产品是否生产完毕的标签,默认情况是没有生产完成。}//生产者class Producer extends Thread{    //产品    Product p;    public Producer(Product p){        this.p=p;    }@Overridepublic void run() {    int i=0;    while(true){        synchronized (p) {            if(p.flag==false){                if(i%2==0){                    p.name="苹果";                    p.price=6.5;                }else{                    p.name="香蕉";                    p.price=2.0;                }                System.out.println("生产者生产出了: "+p.name+"价格是: "+p.price);                p.flag=true;                i++;                p.notifyAll();//唤醒消费者去消费            }else{                //已经生产完毕,等待消费者先去消费                try {                    p.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }}}//消费者class Customer extends Thread{    Product p;    public Customer(Product p){        this.p=p;    }    @Override    public void run() {        while(true){            synchronized (p) {                if(p.flag==true){//产品已经生产完毕                    System.out.println("消费者消费了"+p.name+"价格: "+p.price);                    p.flag=false;                    p.notifyAll();//唤醒生产者去生产                }else{                    //产品还有生产,等待生产者先生产                    try {                        p.wait();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }        }    }}public class Demo {    public static void main(String[] args) {        Product p=new Product();//产品        //创建生产者        Producer producer=new Producer(p);        //创建消费        Customer customer=new Customer(p);        //调用start方法开启线程        producer.start();        customer.start();    }}

队列实现生产者消费者模式:

  • 在Java多线程应用中,队列的使用率很高,多数生产者消费者模型的首选数据结构就是队列(先进先出)。
  • Java提供线程安全的Queue可以分为阻塞式队列和非阻塞式队列
  • 阻塞式队列的典型例子就是BlockingQueue.当前线程没有数据或者数据满了的时候会阻塞。
  • 非阻塞式队列的典型例子就是LinkedList(双向列表)
/*** * Collection(list,set,queue) * @author pjy *  * LinkedList是一个Deque(双重队列)入口可以添加数据,入口也可以移除数据 */public class ThreadCommunictaion01 {    public static void main(String[] args)    throws Exception{        List<String> list=        new ArrayList<String>(2);        list.add("a1");        list.add("a2");        list.add("a3");        list.add("a4");        System.out.println("list.size()="+list.size());        //阻塞式队列        final BlockingQueue<String> q1=        new ArrayBlockingQueue<>(3);        new Thread(){            public void run(){             try{              String s=q1.take();//阻塞式方法,没有数据则等待             //String s=q1.remove();//没有数据会抛出异常              System.out.println("s="+s);              }catch(Exception e){              e.printStackTrace();             }            };        }.start();        q1.put("A");        q1.put("B");        q1.put("C");        //当队列满以后,当前线程会阻塞        q1.put("D");//此方法满了会阻塞        //q1.add("A");此方法满了会抛出异常        System.out.println("q1.size()="+q1.size());    }}

案例:简单的生产者消费者模式:一边放,一边取

  • BlockingQueue队列:
import java.util.Scanner;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;/** * * 生产者:向容器放数据,此容器从键盘读入字符串 * 存储到容器(阻塞式队列)中 * */class Producer extends Thread{//is a    //has a (关联)    private BlockingQueue<String> queue;    public Producer(BlockingQueue<String> queue) {        this.queue=queue;    }    @Override    public void run() {        Scanner sc=new Scanner(System.in);        while(true){            //从键盘读入一个字符串            System.out.println("放数据:");            String s=sc.nextLine();            try{            //将字符串放入容器            queue.put(s);            }catch(Exception e){e.printStackTrace();}        }    }}  /**消费者:从容器中取数据*/class Consumer extends Thread{    //has a (关联)    private BlockingQueue<String> queue;    public Consumer(BlockingQueue<String> queue) {        this.queue=queue;    }    @Override    public void run() {        while(true){          try{          System.out.println("take:"+queue.take());          }catch(Exception e){e.printStackTrace();}        }    }}public class ThreadCommunication02 {    public static void main(String[] args) {        //容器        BlockingQueue<String> container=new LinkedBlockingQueue<String>(3);         //构建线程对象        Producer p=new Producer(container);        Consumer c=new Consumer(container);            //启动线程            p.start();            c.start();            //一边放一边取(简单地生产者消费者模式)    }}
  • LinkedList队列:
import java.util.LinkedList;import java.util.Scanner;import java.util.concurrent.BlockingQueue;/**生产者向容器放数据,此容器从键盘读入字符串 * 存储到容器(非阻塞式队列)中*/class Producer02 extends Thread{//is a    //has a (关联)    private LinkedList<String> queue;    public Producer02(LinkedList<String> queue) {        this.queue=queue;    }    @Override    public void run() {        Scanner sc=new Scanner(System.in);        while(true){            //从键盘读入一个字符串            System.out.println("放数据:");            String s=sc.nextLine();//阻塞方法            synchronized (this) {             try{             //将字符串放入容器             queue.addLast(s);             //通知消费者取             queue.notify();             }catch(Exception e){e.printStackTrace();}            }        }    }}/**消费者从容器中取数据*/class Consumer02 extends Thread{    //has a (关联)    private LinkedList<String> queue;    public Consumer02(LinkedList<String> queue) {        this.queue=queue;    }    @Override    public void run() {        while(true){          synchronized (this) {           //容器内容为空时则等待           if(queue.size()==0)try{queue.wait();}catch(Exception e){}           //取数据           try{           System.out.println("take:"+queue.removeFirst());           }catch(Exception e){e.printStackTrace();}           //通知消费者继续方法           //queue.notify();          }        }    }}public class ThreadCommunication03 {    public static void main(String[] args) {        //容器        LinkedList<String> container=        new LinkedList<String>();         //构建线程对象        Producer02 p=new Producer02(container);        Consumer02 c=new Consumer02(container);        //启动线程        p.start();        c.start();    }}
  • ArrayList:
class Producer03 extends Thread{    @Override    public void run() {        Scanner sc=new Scanner(System.in);        while(true){         String data=sc.nextLine();         //放数据        }    }}class Consumer03 extends Thread{    @Override    public void run() {        while(true){          //取数据        }    }}class Container03{    private List<String> list;    /**@param 容量*/    public Container03(int cap) {        list=new ArrayList<>(cap);    }    /**放数据*/    public synchronized void put(String data){       //1.判断容器是否已满,满则等待       //2.放数据       //3.通知消费者取数据    }    /**取数据*/    public synchronized void take(){       //1.判断容器是否为空,空则等待       //2.取数据       //3.通知生产者放数据    }}public class ThreadCommunication04 {}

wait()与notify()

wait():
等待,如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。

一个线程如果执行了wait方法,那么该线程就会进去一个以锁对象为标识符的线程池中等待。

notify():
唤醒 唤醒等待的方法。

如果一个线程执行了notify方法,那么会唤醒以锁对象为标识符中等待线程中其中一个。

wait与notify方法要注意的事项:
1、wait方法与notify方法是属于Object对象的。
2、wait方法与notify方法必须要在同步代码块或者是同步函数中才能使用。
3、wait方法与notify方法必须要由锁对象调用。

0 0
原创粉丝点击