• java线程之多个生产者消费者


    温故一下上一节所学习的生产者消费者代码:

    两个线程时:

    通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者、一个消费者交替执行的功能

    类名:ProducterConsumerDemo.java

    代码:

     1 class  ProducterConsumerDemo
     2 {
     3     public static void main(String[] args) 
     4     {
     5         Resources  r =new Resources();
     6         Productor  pro =new Productor(r);
     7         Consumer   con = new Consumer(r);
     8         
     9         Thread t1 =new Thread(pro);
    10         Thread t2 =new Thread(con);
    11         t1.start();
    12         t2.start();
    13         System.out.println("Hello World!");
    14     }
    15 }
    16 
    17 class Resources
    18 {
    19     private String name;
    20     private int count =1;
    21     private boolean flag =false;
    22 
    23     public synchronized void set(String name)
    24     {
    25        if(flag)
    26            try{this.wait();}catch(Exception e){}
    27        this.name = name+"--"+count++;
    28 
    29        System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
    30        flag =true;
    31        //唤醒对方进程
    32        this.notify();
    33 
    34     }
    35     public synchronized void out()
    36     {
    37        if(!flag)
    38            try{this.wait();}catch(Exception e){}
    39        
    40        System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
    41        flag =false;
    42        //唤醒对方进程
    43        this.notify();
    44 
    45     }
    46 }
    47 
    48 class Productor implements Runnable
    49 {
    50     private Resources res;
    51     Productor(Resources res){
    52         this.res =res;
    53     }
    54     public void run(){
    55         while(true){
    56             res.set("++商品++");
    57         }
    58     }
    59 
    60 }
    61 
    62 class Consumer  implements Runnable
    63 {
    64     private Resources res;
    65     Consumer(Resources res){
    66         this.res =res;
    67     }
    68     public void run(){
    69         while(true){
    70             res.out();
    71         }
    72     }
    73 
    74 }
    ProducterConsumerDemo.java

    如果再多加上两个线程呢?

      即把其中的ProducterConsumerDemo类改为如下:

    class  ProducterConsumerDemo2
    {
        public static void main(String[] args) 
        {
            Resources  r =new Resources();
            Productor  pro =new Productor(r);
            Consumer   con = new Consumer(r);
            
            Thread t1 =new Thread(pro);
            Thread t2 =new Thread(pro);//多个生产者
            Thread t3 =new Thread(con);
            Thread t4 =new Thread(con);//多个消费者
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            System.out.println("Hello World!");
        }
    }

    运行后发现,加上t3和t4之后结果就错了。

      为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢?

      因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序。

      比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。

      解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。

                               1)把两个方法中的if改为while即可。

               2)需要将notify()改成notifyAll()

    代码:

     1 /*
     2 ProducterConsumerDemo解决了只有两个线程共享资源的生产消费问题,主要利用标志位的互斥解决
     3 
     4 本程序致力于解决多出现多个生产者,多个消费者的时候,依然能够达到生产一次,消费一次的功能
     5  6 解决的方法就是:1)在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。
     7 当然,此时仍会出现问题,就是所以线程都等待,失去资格
     8                 2)需要将notify()改成notifyAll()
     9 */
    10 
    11 class  ProducterConsumerDemo2
    12 {
    13     public static void main(String[] args) 
    14     {
    15         Resources  r =new Resources();
    16         Productor  pro =new Productor(r);
    17         Consumer   con = new Consumer(r);
    18         
    19         Thread t1 =new Thread(pro);
    20         Thread t2 =new Thread(pro);//多个生产者
    21         Thread t3 =new Thread(con);
    22         Thread t4 =new Thread(con);//多个消费者
    23         t1.start();
    24         t2.start();
    25         t3.start();
    26         t4.start();
    27         System.out.println("Hello World!");
    28     }
    29 }
    30 
    31 class Resources
    32 {
    33     private String name;
    34     private int count =1;
    35     private boolean flag =false;
    36 
    37     public synchronized void set(String name)
    38     {  //1)循环判断
    39        while(flag)
    40            try{this.wait();}catch(Exception e){}
    41        this.name = name+"--"+count++;
    42 
    43        System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
    44        flag =true;
    45        //2)唤醒所有进程
    46        this.notifyAll();
    47 
    48     }
    49     public synchronized void out()
    50     {
    51        //1)循环判断
    52        while(!flag)
    53            try{this.wait();}catch(Exception e){}
    54        
    55        System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
    56        flag =false;
    57        //2)唤醒所有进程
    58        this.notifyAll();
    59 
    60     }
    61 }
    62 
    63 class Productor implements Runnable
    64 {
    65     private Resources res;
    66     Productor(Resources res){
    67         this.res =res;
    68     }
    69     public void run(){
    70         while(true){
    71             res.set("++商品++");
    72         }
    73     }
    74 
    75 }
    76 
    77 class Consumer  implements Runnable
    78 {
    79     private Resources res;
    80     Consumer(Resources res){
    81         this.res =res;
    82     }
    83     public void run(){
    84         while(true){
    85             res.out();
    86         }
    87     }
    88 
    89 }

    效果:

  • 相关阅读:
    tomcat 添加用户名和密码
    linux系统下获取cpu、硬盘、内存使用率
    snmp 企业对应的mib编号
    String加密解密 2017.07.26
    Mongo日期
    linux sed 批量替换多个文件中的字符串
    Python和giL的关系
    vim
    乌班图
    Python
  • 原文地址:https://www.cnblogs.com/shuqingstudy/p/5057382.html
Copyright © 2020-2023  润新知