多线程基础回顾(三)-线程通信
生产-消费
规则
- 当库存大于库容时,生产者停止生产,消费者开始消费。
- 当库存小于等于0时,消费者停止消费,生产者开始生产。
-
定义一个仓库
1 class Storehouse { 2 //库容 3 private int max = 20; 4 //当前库存 5 private int currentCount = 0; 6 public void provide(){ 7 currentCount++; 8 System.out.println(Thread.currentThread().getName()+"生产1个,剩余:"+currentCount); 9 } 10 11 public void consume(){ 12 currentCount--; 13 System.out.println(Thread.currentThread().getName()+"消费1个,剩余:"+currentCount); 14 } 15 16 public int getMax() { 17 return max; 18 } 19 20 public int getCurrentCount() { 21 return currentCount; 22 } 23 }
-
生产者类
1 class Provider implements Runnable{ 2 private Storehouse house; 3 4 public Provider(Storehouse house) { 5 this.house = house; 6 } 7 @Override 8 public void run() { 9 synchronized (house) { 10 while(true){ 11 if(house.getCurrentCount() >= house.getMax()){ 12 try { 13 System.out.println("请求消费"); 14 house.notify(); 15 house.wait(); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } 19 }else{ 20 try { 21 Thread.sleep(500); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 house.provide(); 26 } 27 } 28 } 29 } 30 31 }
-
消费者类
1 class Consumer implements Runnable{ 2 private Storehouse house; 3 public Consumer(Storehouse house) { 4 this.house = house; 5 } 6 @Override 7 public void run() { 8 synchronized (house) { 9 while(true){ 10 if(house.getCurrentCount()<=0){ 11 try { 12 System.out.println("请求生产"); 13 house.notify(); 14 house.wait(); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 }else{ 19 try { 20 Thread.sleep(1000); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 house.consume(); 25 26 } 27 } 28 } 29 30 } 31 32 }
-
测试类
1 public class ThreadTest{ 2 public static void main(String[] args) { 3 Storehouse house = new Storehouse(); 4 Provider p = new Provider(house); 5 Consumer c = new Consumer(house); 6 Thread th; 7 th = new Thread(p,"工人"); 8 th.start(); 9 th = new Thread(c,"顾客"); 10 th.start(); 11 } 12 }
线程通信主要通过一个共享对象,此处Storehouse便作为共享对象,作为两个runable实例的共享锁,通过Storehouse.wait()使当前持有它的线程进入等待状态,通过Storehouse.notify唤醒某条拥有该锁的等待线程。
注意事项
-
sleep()和yield()的区别:sleep()使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行;yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行;
-
interrupt():不要以为它是中断某个线程!它只是线线程发送一个中断信号,让线程在无限等待时(如死锁时)能抛出抛出,从而结束线程,但是如果你吃掉了这个异常,那么这个线程还是不会中断的;
-
Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内;
-
obj.wait()与obj.sleep()区别: sleep方法没有释放锁,而wait方法释放了锁;wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用; wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用;