background image

Java 并发编程:同步

线程除要对共享数据保证互斥性访问外,往往还需保证线程的操作按照特定顺序进行。
解决多线程按照特定顺序访问共享数据的技术称作同步。同步技术最常见的编程范式是同
步保护块。这种编程范式在操作前先检测某种条件是否成立,如成立则继续操作;如不成
立则有两种选择,一种是简单的循环检测,直至此条件条件成立:
1 public void guardedOperation(){
2  while(!condition_expression){
3   System.out.println("Not ready yet, I have to wait again!");
4   }
5   }
  这种方法非常消耗 CPU 资源,任何情况下都不应该使用这种方法。另种更好的方式
是条件不成立时调用 Object.wait 方法挂起当前线程,使它一直等待,直至另一个线程
发出激活事件。当然该事件不一定是当前线程希望等待的事件。
1 public synchronized guardedOperation() {
2   while(!condition_expression) {
3   try {
4   wait();
5  } catch (InterruptedException e) {}
6   }
7   System.out.println("Now, condition met and it is ready!");
8   }
  这儿有两点需要特别注意:
  1.要在循环检测中等待条件满足,这是因为中断事件并不一定是当前线程所期望的
事件。线程等待被中断后应该继续检测条件,以便决定是否进入下一轮等待。
  2.当前线程在对 wait 方法调用时,必须是已经获得 wait 方法所属对象的内部锁。也
就 是 说 , wait 方 法 必 须 在 互 斥 块 或 者 互 斥 方 法 体 内 调 用 , 否 则 就 会 发 生
NotOwnerException 错误。这种限制和前面所说的同步前提是互斥的说法是一致的。
  上面代码更通用的写法是:
1 ...
2   synchronized(lock){
3   while(!condition_expression){
4   try{
5   lock.wait();
6   }catch(InterruptedException ie){}
7   }
8  System.out.println("Now, condition met and it is ready!");
9   }
10   ...