java 线程交互之wait/notify
众所周知java支持多线程,有多线程就必然会存在多线程的交互,交互方式有多种,比如通过共享数据,或者通过提供的锁信号量等等,这里通过用wait以及notify实现线程交互。
要用好线程的wait和notify就要首先了解一下线程的状态,线程的状态大致可以划分为一下几种,创建->就绪->运行->阻塞->销毁
一个线程通过new 到调用start完成了创建到就绪,这个之后就是等待cpu分配资源运行,阻塞的状态是发生在线程运行状态之后,发生线程阻塞的情况有很多种,这里简单的列举一下
1>锁阻塞
2>调用wait阻塞
3>调用join阻塞
4>调用sleep阻塞
当然线程也可以从运行状态返回到就绪状态,这个是通过调用Thread类的yeild方法实现的,这里简单说明一下,wait以及notify和notifyall是在超父类Object中提供的,也就是说属于类的
,而sleep/join/yeild是Thread这个类提供的,也即是属于线程的
从上可知,wait以及notify是只能用在对象锁上,不能和共享锁一起使用即只能和synchroized这个关键之一起使用,也就是说用wait和notify之前,必须先获得对象的锁,当调用wait的时候,
线程被放入对象监视器的等待队列里面,而且会释放锁,等待其他线程调用notify从锁对象监视器的等待队列里,取得一个线程执行,记着,synchronized是对象锁,就是说她要锁整个对象。
通过以上我们大致了解了,wait和notify的知识点,下面请看例子,简单的生产者消费者的例子
1 public class Test { 2 3 private static List<Integer> queue = new ArrayList<>(); 4 5 6 /** 7 * 生产者 8 * @param n void 9 * 10 */ 11 public synchronized void producer(int n){ 12 System.out.println("insert data "+n); 13 queue.add(n); 14 15 if(queue.size()==1) 16 this.notify(); 17 } 18 19 /** 20 * 消费者 21 * @return int 22 * 23 */ 24 public synchronized int consumer(){ 25 try { 26 if(queue.isEmpty()) 27 this.wait(); 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } 31 int result = queue.get(0); 32 queue.remove(0); 33 return result; 34 } 35 36 public static void main(String[] args) { 37 final Test test = new Test(); 38 39 Thread thread1 = new Thread(new Runnable() {//生产线程 40 41 @Override 42 public void run() { 43 Random random = new Random(); 44 try { 45 while(true){ 46 test.producer(random.nextInt(1000)); 47 Thread.sleep(2000); 48 } 49 } catch (InterruptedException e) { 50 e.printStackTrace(); 51 } 52 } 53 }); 54 55 Thread thread2 = new Thread(new Runnable() {//消费线程 56 57 @Override 58 public void run() { 59 try { 60 while(true){ 61 System.out.println("select data is "+test.consumer()); 62 Thread.sleep(1000); 63 } 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 } 68 }); 69 70 thread1.start(); 71 thread2.start(); 72 } 73 }
以上是个人的理解,如有误的地方,欢迎大家批评指正,不胜感激