基础模型:
生产者和消费者是一道最为经典的供求案例,而想这供求案例:provider、consumer 在以后进行各种分布式结构开发之后都会被大量采用
现在假设说目的:生产者负责生产一个完整的数据之后,消费者就要把这些数据取走。于是现在假设生产如下的数据:
title=老李 note=是个好人
title=名族败类 note=老方B
范例:编写程序的基础模型
1 package cn.Tony.demo; 2 public class TestDemo { 3 public static void main(String[] args) throws Exception { 4 Data data=new Data(); 5 new Thread(new DataProvider(data)).start(); 6 new Thread(new DataConsumer(data)).start(); 7 } 8 } 9 class DataProvider implements Runnable{ 10 private Data data; 11 public DataProvider(Data data) { 12 this.data=data; 13 } 14 @Override 15 public void run() { 16 for(int x=0;x<50;x++) { 17 if(x%2==0) { 18 this.data.setTitle("老李"); 19 try { 20 Thread.sleep(1000); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 this.data.setNote("是个好人"); 25 }else { 26 this.data.setTitle("民族败类"); 27 try { 28 Thread.sleep(1000); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 this.data.setNote("老方b"); 33 } 34 } 35 } 36 } 37 class DataConsumer implements Runnable{ 38 private Data data; 39 public DataConsumer(Data data) { 40 this.data=data; 41 } 42 @Override 43 public void run() { 44 for(int x=0;x<50;x++) { 45 try { 46 Thread.sleep(1000); 47 } catch (InterruptedException e) { 48 // TODO Auto-generated catch block 49 e.printStackTrace(); 50 } 51 System.out.println(this.data.getTitle()+"="+this.data.getNote()); 52 } 53 } 54 } 55 class Data{//负责数据保存 56 private String title; 57 private String note; 58 public void setNote(String note) { 59 this.note=note; 60 } 61 public String getNote() { 62 return this.note; 63 } 64 public void setTitle(String title) { 65 this.title=title; 66 } 67 public String getTitle() { 68 return this.title; 69 } 70 } 71
这个时候就已经可以发现程序出现两类问题:
数据不完整,明明是好人,结果成败类
数据的重复操作问题(重复设置,或重复取出)
解决重复问题
如果要想解决同步问题,那么可以立刻想到使用synchronized关键字来定义同步的操作方法,所以代码修改如下:
1 package cn.Tony.demo; 2 public class TestDemo { 3 public static void main(String[] args) throws Exception { 4 Data data=new Data(); 5 new Thread(new DataProvider(data)).start(); 6 new Thread(new DataConsumer(data)).start(); 7 } 8 } 9 class DataProvider implements Runnable{ 10 private Data data; 11 public DataProvider(Data data) { 12 this.data=data; 13 } 14 @Override 15 public void run() { 16 for(int x=0;x<50;x++) { 17 if(x%2==0) { 18 this.data.set("老李","老李是个好人"); 19 20 }else { 21 this.data.set("民族败类","老放b"); 22 } 23 } 24 } 25 } 26 class DataConsumer implements Runnable{ 27 private Data data; 28 public DataConsumer(Data data) { 29 this.data=data; 30 } 31 @Override 32 public void run() { 33 for(int x=0;x<50;x++) { 34 this.data.get(); 35 } 36 } 37 } 38 class Data{//负责数据保存 39 private String title; 40 private String note; 41 public synchronized void get() { 42 try { 43 Thread.sleep(50); 44 } catch (InterruptedException e) { 45 // TODO Auto-generated catch block 46 e.printStackTrace(); 47 } 48 System.out.println(this.title+"="+this.note); 49 } 50 public synchronized void set(String title,String note) { 51 this.title=title; 52 try { 53 Thread.sleep(100); 54 } catch (InterruptedException e) { 55 // TODO Auto-generated catch block 56 e.printStackTrace(); 57 } 58 this.note=note; 59 } 60 } 61
于是现在发现,整个的程序里面数据的同步问题得到了很好的,但是重复操作的问题更加严重了,
解决数据的重复操作问题:
如果想要解决重复问题,就要添加唤醒和等待机制,如果想使用这一个功能,那么就要参考Object类中的方法。
等待 死等:public final void wait()throws InterruptedException
唤醒第一个等待线程:public final void notify()
唤醒全部等待线程,那 个优先级高,谁有可能先执行:public final void notifyAll()
范例:通过等待和唤醒机制解决重复操作问题
1 package cn.Tony.demo; 2 public class TestDemo { 3 public static void main(String[] args) throws Exception { 4 Data data=new Data(); 5 new Thread(new DataProvider(data)).start(); 6 new Thread(new DataConsumer(data)).start(); 7 } 8 } 9 class DataProvider implements Runnable{ 10 private Data data; 11 public DataProvider(Data data) { 12 this.data=data; 13 } 14 @Override 15 public void run() { 16 for(int x=0;x<50;x++) { 17 if(x%2==0) { 18 this.data.set("老李","老李是个好人"); 19 20 }else { 21 this.data.set("民族败类","老放b"); 22 } 23 } 24 } 25 } 26 class DataConsumer implements Runnable{ 27 private Data data; 28 public DataConsumer(Data data) { 29 this.data=data; 30 } 31 @Override 32 public void run() { 33 for(int x=0;x<50;x++) { 34 this.data.get(); 35 } 36 } 37 } 38 class Data{//负责数据保存 39 private String title; 40 private String note; 41 //flag=true 表示允许生产不允许消费者取走 42 //flag=false 表示生产完毕允许消费者取走不允许生产 43 private boolean flag=false; 44 public synchronized void get() { 45 if(this.flag==false) {//已经生产了,所以不允许重复生产 46 try { 47 super.wait(); 48 } catch (InterruptedException e1) { 49 // TODO Auto-generated catch block 50 e1.printStackTrace(); 51 }//等待执行 52 } 53 try { 54 Thread.sleep(50); 55 } catch (InterruptedException e) { 56 // TODO Auto-generated catch block 57 e.printStackTrace(); 58 } 59 System.out.println(this.title+"="+this.note); 60 this.flag=false;//表示生产过了。不允许再生产了 61 super.notify();//唤醒等待线程 62 } 63 public synchronized void set(String title,String note) { 64 if(this.flag==true) {//现在不允许取走 65 try { 66 super.wait(); 67 } catch (InterruptedException e) { 68 // TODO Auto-generated catch block 69 e.printStackTrace(); 70 } 71 } 72 this.title=title; 73 try { 74 Thread.sleep(100); 75 } catch (InterruptedException e) { 76 // TODO Auto-generated catch block 77 e.printStackTrace(); 78 } 79 this.note=note; 80 this.flag=true;//继续生产 81 super.notify(); 82 } 83 } 84
面试题:请解释sleep()与wait()的区别
sleep()是Thread类的方法到了一定的时间后该休眠自动唤醒
wait()是Object类中的方法,要想唤醒必须使用notify(),notifyAll()