多线程之11-------线程之间有关协作的方法:wait()与notifyAll()

本文介绍了如何通过互斥锁在并发编程中同步多个线程的操作,确保共享资源的安全访问。重点阐述了使用Object类的wait()和notify()方法在Java中实现线程间安全同步的机制,以及如何通过Condition对象进一步优化同步过程。并通过实例展示了如何设计任务间的握手机制,确保资源的合理分配和高效利用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当使用线程来同时运行多个任务时,可以通过使用锁(互斥) 来同步两个任务的行为,   从而使得一个任务不会干涉另一个任务的资源。 也就是说如果两个任务在交替着步入某项共享资源,  你可以使用互斥来使腹任何时刻只有一个任务可以访问 该资源.

第一步.  当任务协作时, 关键问题是这些任务之间的握手.  为了实现这种握手,要使用线程的基础特性:  互斥。 互斥能够确保只有一个任务可以响应某个信号,这样可以去除 任何可能的竞争条件。  在互斥基础上,我们为任务添加了一种途么,可以将其自身挂起,直至某些外部条件发生变化, 表示是时候让这个任务再接着运行了。

第二步. 任务间的握手,可以通过Object 的 wait()和 notify() 来安全地实现,  在Java的并发类库中, 还提供了具有 await()  和 signal()  方法的Condition对象.

第三步. wait()  可以等待某个条件发生变化,   很显然,改变这个条件超出了当前方法的控制能力.  通常这种条件将由另一个任务来改变.

          因此,  wait()  提供了一种在任务之间对活动同步的方式, 即让操作按顺序 一步一步执行。

         调用sleep() 时,锁并没有被释放, yield()  也属于这种情况. 另一方面看, 当一个任务在方法里遇到了对wait ()  的调用的时候, 线程的执行被挂起,对象上的锁被释放。 这就意味着另一个任务可以获得这个锁。

       (1)  有两种形式的wait().  第一种形式使用毫秒作为参数, 表示经此期间暂停, 与sleep()  不同的是, 对于wait() 而言:

        a.   在wait() 期间对象锁是释放的

        b.   可以通过nofity(),  notifyAll(), 或者令时间到期, 从wait() 中恢复执行.

        第二种形式,更常用的wait()  不带参数, 这种wait() 将无限等待下去, 直到接收到 notify(),  notifyAll()  消息

   注意: 从wait(),  notify(),  notifyAll()属于Object 的方法可知, 可以把wait()放进任何同步控制方法里, 而不用考虑该类是否与Thread,   Runnable有关 .  实际上,只能在同步控制流程里调用wait(), notify(),  notifyAll(),  如果在非同步控制方法里调用, 程序运行时将 抛出  illegalMonitorStateException,并伴随一些含糊的信息,  比如  "当前线程不是拥有者"  , 异常信息表示:  调用 wait(),  notify() 和notifyAll() 的任务在调用这些方法前必须  "拥有" 对象的锁


第四步.    可以让一个对象执行某种操作以维护其自己的锁。  必须首先得到对象的锁,  如果要向对象 x  发送notifyAll(),  那么就必须在能够取得x  的锁的同步控制块中 这么做:

synchronized(x)  {

      x.notifyAll();  


现在看一个简单的示例,  业务:执行两个操作,一个将蜡涂(wax)在汽车上, 一个抛光它,  抛光(buff)任务在涂蜡任务完成之前,是不能执行的, 而涂蜡任务在涂另一层蜡之前必须等待抛光完成, 示意图:


WaxOn 和WaxOff 都使用了Car 对象,该对象在这些任务等待条件变化的时候,使用wait() 和notifyAll() 来挂起和重新启动这些任务.

package concurrency.waxomatic;
import java.util.concurrent.*;
import static net.mindview.util.Print.*;

class Car {
  private boolean waxOn = false;
  public synchronized void waxed() {    //"涂蜡" 动作 
    waxOn = true; // Ready to buff
    notifyAll();
  }
  public synchronized void buffed() {    //"抛光"  动作
    waxOn = false; // Ready for another coat of wax
    notifyAll();
  }
  public synchronized void waitForWaxing()
  throws InterruptedException {
    while(waxOn == false)
      wait();
  }
  public synchronized void waitForBuffing()
  throws InterruptedException {
    while(waxOn == true)
      wait();
  }
}

class WaxOn implements Runnable {     //涂蜡
  private Car car;
  public WaxOn(Car c) { car = c; }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        printnb("Wax On! ");
        TimeUnit.MILLISECONDS.sleep(200);
        car.waxed();
        car.waitForBuffing();            //等待抛光
      }
    } catch(InterruptedException e) {
      print("Exiting via interrupt");
    }
    print("Ending Wax On task");
  }
}

class WaxOff implements Runnable {    //抛光
  private Car car;
  public WaxOff(Car c) { car = c; }
  public void run() {
    try {
      while(!Thread.interrupted()) {
        car.waitForWaxing();           //等待涂蜡
        printnb("Wax Off! ");
        TimeUnit.MILLISECONDS.sleep(200);
        car.buffed();
      }
    } catch(InterruptedException e) {
      print("Exiting via interrupt");
    }
    print("Ending Wax Off task");
  }
}

public class WaxOMatic {
  public static void main(String[] args) throws Exception {
    Car car = new Car();
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new WaxOff(car));
    exec.execute(new WaxOn(car));
    TimeUnit.SECONDS.sleep(5); // 运行5秒钟 时长
    exec.shutdownNow(); // Interrupt all tasks
  }
}

下载代码请参见:  http://mindview.net/Books/TIJ4


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值