基础模型:
生产者和消费者是一道最为经典的供求案例,而想这供求案例: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 @Override15 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 @Override43 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 block49 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 @Override15 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 @Override32 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 block46 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 block56 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 @Override15 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 @Override32 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 block50 e1.printStackTrace();51 }//等待执行 52 }53 try {54 Thread.sleep(50);55 } catch (InterruptedException e) {56 // TODO Auto-generated catch block57 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 block69 e.printStackTrace();70 }71 }72 this.title=title;73 try {74 Thread.sleep(100);75 } catch (InterruptedException e) {76 // TODO Auto-generated catch block77 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()