多线程之间的通信
线程通信的概念:
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会使开发人员对线程任务在处理的过程中进行有效的把控与监督。
使用wait/notify方法实现线程间的通信(这两个方法都是object的类的方法,换句话说java为所有的对象 都提供了这两个方法)1.1.wait和notify必须配合synchronized关键字使用
2.wait方法释放锁,notify方法不释放锁。
代码1:最原始的实现方式 缺点:线程2一直在判断list的size,每增加一个判断一次
1 package com.java.day02_notify_wait; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class ListAdd1 { 7 private volatile static List list = new ArrayList(); 8 9 public void add() { 10 list.add("nanami"); 11 } 12 13 public int getSize() { 14 return list.size(); 15 } 16 17 public static void main(String[] args) { 18 final ListAdd1 a = new ListAdd1(); 19 20 Thread t1 = new Thread(new Runnable() { 21 public void run() { 22 for (int i = 0; i < 10; i++) { 23 a.add(); 24 System.out.println(Thread.currentThread().getName() + "线程增加了一个元素"); 25 try { 26 Thread.sleep(500); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 } 31 32 } 33 }, "t1"); 34 35 Thread t2 = new Thread(new Runnable() { 36 public void run() { 37 while(true){ 38 if(a.getSize()==5){//线程2收到通知 39 System.out.println(Thread.currentThread().getName()+"线程收到通知:"+"list.size()=5 "+"线程停止。。。。。。。"); 40 throw new RuntimeException(); 41 } 42 } 43 44 } 45 }, "t2"); 46 47 t1.start(); 48 t2.start(); 49 50 } 51 52 }
运行结果:
1 t1线程增加了一个元素 2 t1线程增加了一个元素 3 t1线程增加了一个元素 4 t1线程增加了一个元素 5 t1线程增加了一个元素 6 Exception in thread "t2" java.lang.RuntimeException 7 t2线程收到通知:list.size()=5 线程停止。。。。。。。 8 at com.java.day02_notify_wait.ListAdd1$2.run(ListAdd1.java:40) 9 at java.lang.Thread.run(Unknown Source) 10 t1线程增加了一个元素 11 t1线程增加了一个元素 12 t1线程增加了一个元素 13 t1线程增加了一个元素 14 t1线程增加了一个元素
代码2:用wait和notify实现 弊端:不时实问题
注意:先执行线程2,再执行线程1
1 package com.java.day02_notify_wait; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class ListAdd2 { 7 private volatile static List list = new ArrayList(); 8 9 public void add(){ 10 list.add("tomoe"); 11 } 12 13 public int getSize(){ 14 return list.size(); 15 } 16 17 18 public static void main(String[] args) { 19 final Object lock = new Object(); 20 final ListAdd2 list = new ListAdd2(); 21 22 Thread t1 = new Thread(new Runnable() { 23 public void run() { 24 synchronized (lock) { 25 for (int i = 0; i < 10; i++) { 26 list.add(); 27 System.out.println(Thread.currentThread().getName()+"线程添加了一个元素"); 28 try { 29 Thread.sleep(500); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 if(list.getSize()==5){ 34 System.out.println("通知已发出"); 35 lock.notify(); 36 } 37 38 } 39 } 40 } 41 },"t1"); 42 43 44 Thread t2 = new Thread(new Runnable() { 45 public void run() { 46 synchronized (lock) { 47 if(list.getSize()!=5){ 48 try { 49 lock.wait(); 50 } catch (InterruptedException e) { 51 e.printStackTrace(); 52 } 53 } 54 System.out.println("收到线程通知:"+"list.size()=5"+" 线程停止。。。"); 55 throw new RuntimeException(); 56 } 57 } 58 },"t2"); 59 60 t2.start(); 61 t1.start(); 62 63 /** 64 * 代码执行流程 65 * 1.线程2先启动,获得lock锁,执行wait语句,释放锁 66 * 2.线程1启动后获得lock锁,唤醒线程2,但是不会释放锁,当synchronized中的语句执行完后,会释放锁 67 * 68 * 如果t1先执行,则t1先获得锁,t1在执行notify时,t2并没有wait,在t1执行完之后,执行t2,此时,t2进入wait,并没有被唤醒 69 */ 70 71 72 } 73 74 75 }
运行结果: 当线程1执行完后释放锁,线程2才可以执行
1 t1线程添加了一个元素 2 t1线程添加了一个元素 3 t1线程添加了一个元素 4 t1线程添加了一个元素 5 t1线程添加了一个元素 6 通知已发出 7 t1线程添加了一个元素 8 t1线程添加了一个元素 9 t1线程添加了一个元素 10 t1线程添加了一个元素 11 t1线程添加了一个元素 12 收到线程通知:list.size()=5 线程停止。。。 13 Exception in thread "t2" java.lang.RuntimeException 14 at com.java.day02_notify_wait.ListAdd2$2.run(ListAdd2.java:55) 15 at java.lang.Thread.run(Unknown Source)
代码3:实时通知
1 package com.java.day02_notify_wait; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.CountDownLatch; 6 7 public class ListAdd3 { 8 private volatile static List list = new ArrayList (); 9 public void add(){ 10 list.add("nanami"); 11 } 12 13 public int getsize(){ 14 return list.size(); 15 } 16 17 private static CountDownLatch countdownlatch = new CountDownLatch(1); 18 19 20 public static void main(String[] args) { 21 final ListAdd3 list = new ListAdd3(); 22 23 Thread t1 = new Thread(new Runnable() { 24 public void run() { 25 for (int i = 0; i < 10; i++) { 26 list.add(); 27 System.out.println(Thread.currentThread().getName()+"线程增加了一个元素"); 28 try { 29 Thread.sleep(500); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 if(list.getsize()==5){ 34 System.out.println("发出通知");
//private static CountDownLatch countdownlatch = new CountDownLatch(1);这里写的数字1,则下面的语句写一遍,如果为数字2,则唤醒的语句写两遍 35 countdownlatch.countDown(); //1 36 // countdownlatch.notify(); //2 37 38 } 39 } 40 } 41 },"t1"); 42 43 44 Thread t2 = new Thread(new Runnable() { 45 public void run() { 46 if(list.getsize()!=5){ 47 try { 48 countdownlatch.await(); 49 } catch (InterruptedException e) { 50 e.printStackTrace(); 51 } 52 } 53 System.out.println("接到通知:"+"list.size()=5"+" 线程停止"); 54 throw new RuntimeException(); 55 } 56 },"t2"); 57 58 t1.start(); 59 t2.start(); 60 61 } 62 63 64 65 66 67 }
运行结果1:运行完成,程序结束
1 t1线程增加了一个元素 2 t1线程增加了一个元素 3 t1线程增加了一个元素 4 t1线程增加了一个元素 5 t1线程增加了一个元素 6 发出通知 7 t1线程增加了一个元素 8 接到通知:list.size()=5 线程停止 9 Exception in thread "t2" java.lang.RuntimeException 10 at com.java.day02_notify_wait.ListAdd3$2.run(ListAdd3.java:54) 11 at java.lang.Thread.run(Unknown Source) 12 t1线程增加了一个元素 13 t1线程增加了一个元素 14 t1线程增加了一个元素 15 t1线程增加了一个元素
运行结果2:运行未终止