线程间同步说的通俗一点讲就是两点:
1. 当某个线程处理好数据后能通知其他线程自己活干完了,然后别的线程能使用它处理好的数据做其他事情。(Object.notify, Object.notifyAll)
2. 某个线程需要其他线程的计算结果时,需要等待知道别的线程把活干完了,它拿到数据开始干自己的活。(Object.wait)
java对并发的支持很全面,而且直接在基类Object里面提供了支持,最常用的三种方法列举如下(上面其实已经提到了):
1. Object.notify:通知某个线程自己活干好了,兄弟可以开工了。某个调用了此对象的wait方法的线程将停止阻塞,返回。
2. Object.notifyAll:通知所有线程自己活干好了。所有调用了此对象wait方法的线程都将停止阻塞,返回。
3. Object.wait:等待其它线程活干完了,自己再开工。此方法将阻塞,直到某个线程调用了notify或者notifyAll为止。
下面是个简单的例子,例子的用意是三个线程A、B、C一起干活,每一次工序需要A先干完然后B开工,B干完然后C开工,然后进入下一个工序、如此反复。
流程图:
Java代码
1 /** 2 * 并发打印类 3 * @author shun.li 4 */ 5 static class ConcurrentPrinter implements Runnable 6 { 7 8 //线程互斥变量 9 private static Object mutex = new Object(); 10 //当前获得打印资格的线程的名字 11 private static String currentName = ""; 12 public static void setCurrentName(String name) { 13 currentName = name; 14 } 15 16 private String name; //本线程名字 17 private String nextName;//下一个可打印的线程名 18 private int count; //打印次数 19 20 public ConcurrentPrinter(String name, String nextName, int count) { 21 this.name = name; 22 this.nextName = nextName; 23 this.count = count; 24 } 25 26 /** 27 * 打印信息,打印次数为 28 */ 29 public void print() { 30 //:打印互斥,各个线程只有一个打印完了下一个才可以开始 31 synchronized(mutex) { 32 33 //:等待上一个线程通知自己可以打印 34 while(currentName != name) { 35 try { 36 mutex.wait(); 37 } catch (InterruptedException e) { 38 return; 39 } 40 } 41 //:打印 42 for(int i = 0; i < count; ++i) { 43 System.out.println(String.format("%1$04d:%2$s",i,name)); 44 } 45 //设置可执行线程名为下一个 46 currentName = nextName; 47 //通知所有线程,名为currentName的线程符合条件,将开始打印 48 mutex.notifyAll(); 49 } 50 } 51 52 @Override 53 public void run() { 54 //各个线程先后执行打印任务100次 55 for(int i = 0; i < 10; ++i) { 56 this.print(); 57 } 58 } 59 } 60 61 /** 62 * @param args 63 * @throws IOException 64 */ 65 public static void main(String[] args) { 66 System.out.println("alala"); 67 68 //:创建3个线程,轮流打印 69 Thread aThread = new Thread(new ConcurrentPrinter("A","B",3)); 70 Thread bThread = new Thread(new ConcurrentPrinter("B","C",3)); 71 Thread cThread = new Thread(new ConcurrentPrinter("C","A",3)); 72 ConcurrentPrinter.setCurrentName("A"); 73 aThread.start(); 74 bThread.start(); 75 cThread.start(); 76 }