博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 实践:生产者与消费者
阅读量:5311 次
发布时间:2019-06-14

本文共 6515 字,大约阅读时间需要 21 分钟。

实践项目:生产者与消费者【经典多线程问题】

问题引出:

  生产者和消费者指的是两个不同的线程类对象,操作同一个空间资源的情况。

需求引出:

  —— 生产者负责生产数据,消费者负责取走数据

  —— 生产者生产完一组数据之后,消费者就要取走一组数据

 

设置三个类:数据类、生产类、消费类;生产和消费类是线程类,同时操作同一个数据类;生产类负责每次向数据类中写入一组数据;消费类负责每次从数据类中取出一组数据。

1 package hello; 2  3 class Info {  // 数据类 4     private String title ; 5     private String content; 6     public void setTitle(String title) { 7         this.title = title ;  8     } 9     public String getTitle() {10         return title ;11     }12     public String getContent() {13         return content ;14     }15     public void setContent(String content) {16         this.content = content ;17     }18     19 }20 21 class Producer implements Runnable { // 生成者类(线程)22     private Info info ;23     public Producer(Info info) {24         this.info = info ;25     }26     @Override27     public void run() {28         for (int x = 0 ; x < 100 ; x ++ ) {29             try {30                 Thread.sleep(200);31             } catch (InterruptedException e) {32                 e.printStackTrace();33             }34             if ( x % 2 == 0 ) {35                 this.info.setTitle("张三");36                 this.info.setContent("男");37             } else {38                 this.info.setTitle("王五");39                 this.info.setContent("男");40             }41         }42     }43 }44 45 class Consumer implements Runnable {46     private Info info ; 47     public Consumer(Info info) {48         this.info = info ;49     }50     @Override51     public void run() {52         for (int x = 0 ; x < 100 ; x ++) {53             try {54                 Thread.sleep(100);55             } catch (InterruptedException e) {56                 e.printStackTrace();57             }58             System.out.println(this.info.getTitle() + "——" + this.info.getContent());59         }60     }61 }62 63 public class TestDemo {64     public static void main(String[] args) throws Exception {65         Info info = new Info() ;66         new Thread(new Producer(info)).start();67         new Thread(new Consumer(info)).start();68     }69 }

 上例程序执行后,会发现“错位的现象”;出现类似数据为取走,就存入新的数据的错误。【不同步且异步现象导致】

1 package hello; 2  3 class Info {  // 数据类 4     private String title ; 5     private String content; 6     public synchronized void set(String title , String content) { 7         this.title = title ; 8         try { 9             Thread.sleep(100);10         } catch (InterruptedException e) {11             e.printStackTrace();12         }13  14         this.content = content ;15     }16     public synchronized void get() {17         try {18             Thread.sleep(100);19         } catch (InterruptedException e) {20             e.printStackTrace();21         }22         System.out.println(this.title + "——" + this.content);23     }24     25 }26 27 class Producer implements Runnable { // 生成者类(线程)28     private Info info ;29     public Producer(Info info) {30         this.info = info ;31     }32     @Override33     public void run() {34         for (int x = 0 ; x < 100 ; x ++ ) {                              35             if ( x % 2 == 0 ) {36                 this.info.set("张三", "男");37             } else {38                 this.info.set("李悦", "女");39             }40         }41     }42 }43 44 class Consumer implements Runnable {45     private Info info ; 46     public Consumer(Info info) {47         this.info = info ;48     }49     @Override50     public void run() {51         for (int x = 0 ; x < 100 ; x ++) {52             this.info.get();53         }54     }55 }56 57 public class TestDemo {58     public static void main(String[] args) throws Exception {59         Info info = new Info() ;60         new Thread(new Producer(info)).start();61         new Thread(new Consumer(info)).start();62     }63 }

 

通过“同步方法”,解决了数据不同步的问题,但是于此而来的问题就是:数据的重复操作。

针对上两例程序,我们通过Object类的支持,来解决数据重复操作的问题:

  如果像上例的设计,需要在程序中加入一个等待机制;当数据未取则等待数据取出后在存入,当数据未存等待数据存入后取出。而Object类中提供有专门的“等待”。

 

 

 

等待:    public final void wait() throws InterruptedException
唤醒第一个等待线程:    public final void notify() ;
唤醒全部的等待进入:    public final void notifyAll();  //优先级高越有可能先唤醒

 

 

通过Object的线程等待和唤醒功能完善程序:

1 package hello; 2  3 class Info {  // 数据类 4     private String title ; 5     private String content; 6     private boolean flag = true ; 7     // true:表示可以生产,不可以取走 8     // false:表示不可以生产,可以取走 9     public synchronized void set(String title , String content) {10         if (this.flag == false) { // 发现不可以生产,则等待线程11             try {12                 super.wait();  // 通过super调用自己的超类(父类)Object类中的wait()方法等待线程13             } catch (InterruptedException e) {14                 e.printStackTrace();15             }16         }17         this.title = title ;18         try {19             Thread.sleep(100);20         } catch (InterruptedException e) {21             e.printStackTrace();22         }23         this.content = content ;24         this.flag = false ;// 修改标记25         super.notify(); //唤醒其他等待线程26     }27     public synchronized void get() {28         if (this.flag == true) {29             try {30                 super.wait();31             } catch (InterruptedException e) {32                 e.printStackTrace();33             }34         }35         try {36             Thread.sleep(100);37         } catch (InterruptedException e) {38             e.printStackTrace();39         }40         System.out.println(this.title + "——" + this.content);41         this.flag = true ; //修改标记42         super.notify(); // 唤醒其他线程43     }44     45 }46 47 class Producer implements Runnable { // 生成者类(线程)48     private Info info ;49     public Producer(Info info) {50         this.info = info ;51     }52     @Override53     public void run() {54         for (int x = 0 ; x < 100 ; x ++ ) {                              55             if ( x % 2 == 0 ) {56                 this.info.set("张三", "男");57             } else {58                 this.info.set("李悦", "女");59             }60         }61     }62 }63 64 class Consumer implements Runnable {65     private Info info ; 66     public Consumer(Info info) {67         this.info = info ;68     }69     @Override70     public void run() {71         for (int x = 0 ; x < 100 ; x ++) {72             this.info.get();73         }74     }75 }76 77 public class TestDemo {78     public static void main(String[] args) throws Exception {79         Info info = new Info() ;80         new Thread(new Producer(info)).start();81         new Thread(new Consumer(info)).start();82     }83 }

 

 我们依靠Object类中的等待唤醒机制完成了代码的要求。

 

 

 

 

------------------------

转载于:https://www.cnblogs.com/wangyuyang1016/p/10959373.html

你可能感兴趣的文章
Junit使用教程(一)
查看>>
Python接口测试-使用requests模块发送post请求
查看>>
混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。...
查看>>
jQuery总结或者锋利的jQuery笔记二
查看>>
前后端协作--服务器渲染与前后端分离
查看>>
微软职位内部推荐-Sr. SE - Office incubation
查看>>
微软职位内部推荐-SOFTWARE ENGINEER II
查看>>
GDB调试
查看>>
centos系统python2.7更新到3.5
查看>>
一个通用的单元测试框架的思考和设计09-实现篇-视图操作
查看>>
互联网移动业务服务端系统架构设计演化
查看>>
【Quartz】常用方法的使用方式(三)
查看>>
MVVM模式下关闭窗口的实现
查看>>
背水一战 Windows 10 (11) - 资源: CustomResource, ResourceDictionary, 加载外部的 ResourceDictionary 文件...
查看>>
SqlServer 更改复制代理配置文件参数及两种冲突策略设置
查看>>
美妆算法---人脸审美标准
查看>>
C#区域截图——调用API截图
查看>>
c#与java中byte字节的区别及转换方法
查看>>
ArcGIS API for Silverlight 调用GP服务准备---GP模型建立、发布、测试
查看>>
A WebBrowser Toy
查看>>