先不多说,直接上个例子,著名的生产者消费者问题。
1 public class ProducerConsumer { 2 public static void main(String[] args) { 3 SyncStack ss = new SyncStack(); 4 Producer p = new Producer(ss); 5 Consumer c = new Consumer(ss); 6 new Thread(p).start();//生产者线程 7 new Thread(c).start();//消费者线程 8 } 9 } 10 /** 11 消费的物品---窝头 12 **/ 13 class WoTou { 14 int id; 15 WoTou(int id) { 16 this.id = id; 17 } 18 public String toString() { 19 return "WoTou : " + id; 20 } 21 } 22 /** 23 消费的空间---堆栈 24 **/ 25 class SyncStack { 26 int index = 0; 27 WoTou[] arrWT = new WoTou[6]; 28 29 public synchronized void push(WoTou wt) { 30 while(index == arrWT.length) {//是while而不是if的原因,当wait被打断的时候依旧要检查下堆栈是否满了 31 try { 32 this.wait(); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 } 37 this.notifyAll(); 38 arrWT[index] = wt; 39 index ++; 40 } 41 42 public synchronized WoTou pop() { 43 while(index == 0) { 44 try { 45 this.wait(); 46 } catch (InterruptedException e) { 47 e.printStackTrace(); 48 } 49 } 50 this.notifyAll(); 51 index--; 52 return arrWT[index]; 53 } 54 } 55 56 /** 57 生产者类 58 **/ 59 class Producer implements Runnable { 60 SyncStack ss = null; 61 Producer(SyncStack ss) { 62 this.ss = ss; 63 } 64 65 public void run() { 66 for(int i=0; i<20; i++) { 67 WoTou wt = new WoTou(i); 68 ss.push(wt); 69 System.out.println("生产了:" + wt); 70 try { 71 Thread.sleep((int)(Math.random() * 200)); 72 } catch (InterruptedException e) { 73 e.printStackTrace(); 74 } 75 } 76 } 77 } 78 /** 79 消费者类 80 **/ 81 class Consumer implements Runnable { 82 SyncStack ss = null; 83 Consumer(SyncStack ss) { 84 this.ss = ss; 85 } 86 87 public void run() { 88 for(int i=0; i<20; i++) { 89 WoTou wt = ss.pop(); 90 System.out.println("消费了: " + wt); 91 try { 92 Thread.sleep((int)(Math.random() * 1000)); 93 } catch (InterruptedException e) { 94 e.printStackTrace(); 95 } 96 } 97 } 98 }
效果如图:
synchronized的引入,学过数据库系统和操作系统的朋友应该会有所了解,对于共享资源,当一个线程占用的时候不能被其他线程操作,和操作系统的原子操作的原理有些相似。当synchronized之后,就会获得对象锁,其他线程就无法获得对象锁。
wait的引入:例如上题堆栈中只能放6个窝头,但是当堆栈中有6个窝头的时候,生产者获得对象锁的时候就不能生产了,因此,生产者就会进入wait池,同时又会释放对象锁。
notify的引入:唤醒wait池中的一个线程(ps:只能唤醒别的线程,不能唤醒自己)
notifyall的引入:唤醒wait池中的所有线程
在最后,给大家说下wait和sleep的区别吧,个人理解:
1.wait是Object类中方法,会抛出InteruptException,sleep是Thread类中的方法,wait方法只用在获得对象所得时候才能用,否则会抛异常;
2.wait方法会释放对象锁,但是sleep不会释放对象锁;
3.wait后的线程需要其他的线程去唤醒,但是sleep的线程在规定的时间后会自动唤醒。
时间: 2024-10-11 21:19:59