zoukankan      html  css  js  c++  java
  • JDK 5.0 Concurrency Utilities 并发处理(2)Condition 条件变量

    Condition 条件变量

    条件变量是线程同步对象中的一种,主要用来等待某种条件的发生,条件发生后,可以唤醒等待在该条件上的一个线程,或所有线程。条件变量要与锁一起协同工作。

    条件变量调用Lock.newCondition()获得一个实例:

    ReentrantLock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    通常的调用方式如下:

    // 当条件 con == true 时等待
    lock.lock();

    try {
        if (con == true) {
            condition.await();
        }

        // do something
    } finally {
        lock.unlock();
    }

    // 条件变量的唤醒:
    condition.signal(); //唤醒等待的其中一个线程
    condition.signalAll(); //唤醒等待的所有线程

    条件变量类似JDK1.4或以前版本中的 Object.wait(); Object.notify(); Object.notifyAll();

    值得注意的是当condition.await()时,隐式的将条件变量关联的Lock解锁,而使其他线程有机会获得Lock,而检查条件,并在条件满足时,等待在条件变量上。

    我们先来看一下没有条件变量时,传统的处理方式:
    下面这个例子,创建3个等候线程,每个线程循环调用event.wait(), 等到了event后,显示相应的信息。
    然后创建1个通知线程,每隔1秒调用 event.notify() 通知等待线程。

    import java.util.Calendar;

    public class TestWait {

     // 创建event Object,以使用它的wait(), notify()等方法
     private Object event = null;
     
     public TestWait() {
      // 创建event
      event = new Object();
     }
     
     public static void main(String[] args) {

      TestWait tester = new TestWait();
     
      tester.test();
     }

     public Object getEvent() {
      return event;
     }
     
     public void test() {
      // 启动3个等候线程
      new Thread(new WaitThread(this)).start();
      new Thread(new WaitThread(this)).start();
      new Thread(new WaitThread(this)).start();
     
      // 启动通知线程
      new Thread(new NotifyThread(this)).start();
     }
    }

    class WaitThread implements Runnable {
     
     private TestWait tester = null;
     
     public WaitThread(TestWait tester) {
      this.tester = tester;
     }
     
     public void run() {
      Calendar now = Calendar.getInstance();
     
      System.out.println(now.getTime() + " W " + Thread.currentThread() + " wait for event.");
     
      while (true) {
      
       try {
        // 同步访问 event
        synchronized (tester.getEvent()) {
         // 等待在 event 上
         tester.getEvent().wait();
        }
       
        // 等到 event 后,显示信息 "got event"
        Calendar now1 = Calendar.getInstance();
        System.out.println(now1.getTime() + " W " + Thread.currentThread() + " got event.");

        // do something ...
        Thread.sleep(500);

       } catch (Exception e) {
        e.printStackTrace();
       }
      }
     }
    }

    class NotifyThread implements Runnable {
     
     private TestWait tester = null;
     
     public NotifyThread(TestWait tester) {
      this.tester = tester;
     }
     
     public void run() {
     
      while (true) {
      
       try {
        // 间隔1秒
        Thread.sleep(1000);
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      
       // 同步访问 event
       synchronized (tester.getEvent()) {
        // 通知等在event上的一个线程
        tester.getEvent().notify();

        // 通知等在event上的所有线程
        // tester.getEvent().notifyAll();
          
        // 打印 "fire event" 信息。
        Calendar now = Calendar.getInstance();
        System.out.println(now.getTime() + " N " + Thread.currentThread() + " fire event.");
       }
      }
     }
    }

    程序运行结果如下:

    Tue Jan 24 14:42:31 CST 2006 W Thread[Thread-0,5,main] wait for event.
    Tue Jan 24 14:42:31 CST 2006 W Thread[Thread-2,5,main] wait for event.
    Tue Jan 24 14:42:31 CST 2006 W Thread[Thread-1,5,main] wait for event.
    Tue Jan 24 14:42:31 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 14:42:31 CST 2006 W Thread[Thread-0,5,main] got event.
    Tue Jan 24 14:42:32 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 14:42:32 CST 2006 W Thread[Thread-2,5,main] got event.
    Tue Jan 24 14:42:33 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 14:42:33 CST 2006 W Thread[Thread-1,5,main] got event.
    Tue Jan 24 14:42:34 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 14:42:34 CST 2006 W Thread[Thread-0,5,main] got event.
    Tue Jan 24 14:42:36 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 14:42:36 CST 2006 W Thread[Thread-2,5,main] got event.

    前三行启动3个等候线程,线程阻塞在 event.wait()上。
    第四行通知线程Thread-3,调用event.notify();
    第五行Thread-0线程,got event.
    一秒钟后,Thread-3,又触发了event.notify();

    下面将NotifyThread中的 event.notify(); 改为event.notifyAll(); 看一下运行结果:

    Tue Jan 24 15:25:43 CST 2006 W Thread[Thread-1,5,main] wait for event.
    Tue Jan 24 15:25:43 CST 2006 W Thread[Thread-2,5,main] wait for event.
    Tue Jan 24 15:25:43 CST 2006 W Thread[Thread-0,5,main] wait for event.
    Tue Jan 24 15:25:44 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 15:25:44 CST 2006 W Thread[Thread-1,5,main] got event.
    Tue Jan 24 15:25:44 CST 2006 W Thread[Thread-0,5,main] got event.
    Tue Jan 24 15:25:44 CST 2006 W Thread[Thread-2,5,main] got event.
    Tue Jan 24 15:25:45 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 15:25:45 CST 2006 W Thread[Thread-0,5,main] got event.
    Tue Jan 24 15:25:45 CST 2006 W Thread[Thread-1,5,main] got event.
    Tue Jan 24 15:25:45 CST 2006 W Thread[Thread-2,5,main] got event.
    Tue Jan 24 15:25:46 CST 2006 N Thread[Thread-3,5,main] fire event.
    Tue Jan 24 15:25:46 CST 2006 W Thread[Thread-1,5,main] got event.
    Tue Jan 24 15:25:46 CST 2006 W Thread[Thread-0,5,main] got event.
    Tue Jan 24 15:25:46 CST 2006 W Thread[Thread-2,5,main] got event.

    可以看到当Thread-3,event.notifyAll(); 所有的线程都 got event.


    接下来,我们将这个例子改写为使用条件变量的例子:

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;

    public class TestCondition {

     private ReentrantLock lock = null;
     private Condition condition = null;
     
     public TestCondition() {
      lock = new ReentrantLock();
      condition = lock.newCondition();
     }

     public static void main(String[] args) {
      
      TestCondition tester = new TestCondition();

      tester.test();
     }
     
     public void test() {
      new Thread(new WaitThread1(this)).start();
      new Thread(new WaitThread1(this)).start();
      new Thread(new WaitThread1(this)).start();

      new Thread(new NotifyThread1(this)).start();
     }

     public ReentrantLock getLock() {
      return lock;
     }
     
     public Condition getCondition() {
      return condition;
     }
    }

    class NotifyThread1 implements Runnable {
     
     private TestCondition tester = null;
     
     public NotifyThread1(TestCondition tester) {
      this.tester = tester;
     }
     
     public void run() {
      while (true) {
       try {
        Thread.sleep(2000);
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
       
       tester.getLock().lock();
       
       tester.getCondition().signal();
       System.out.println(Thread.currentThread() + " condition signal.");
       
       tester.getLock().unlock();
      }
     }
    }

    class WaitThread1 implements Runnable {
     
     private TestCondition tester = null;
     
     public WaitThread1(TestCondition tester) {
      this.tester = tester;
     }
     
     public void run() {
      System.out.println(Thread.currentThread() + " started.");

      while (true) {
       tester.getLock().lock();

       try {
        // getCondition().await() 将使getLock()解锁,以便其他线程可以进入 await();
        tester.getCondition().await();

        System.out.println(Thread.currentThread() + " get condition.");
       } catch (InterruptedException e) {
        e.printStackTrace();
       } finally {
        tester.getLock().unlock();
       }
      }
     }
    }

    运行结果如下:

    Thread[Thread-0,5,main] started.
    Thread[Thread-1,5,main] started.
    Thread[Thread-2,5,main] started.
    Thread[Thread-3,5,main] condition signal.
    Thread[Thread-0,5,main] get condition.
    Thread[Thread-3,5,main] condition signal.
    Thread[Thread-1,5,main] get condition.
    Thread[Thread-3,5,main] condition signal.
    Thread[Thread-2,5,main] get condition.
    Thread[Thread-3,5,main] condition signal.
    Thread[Thread-0,5,main] get condition.

  • 相关阅读:
    20位活跃在Github上的国内技术大牛
    ubuntu下安装ros出现“无法下载-package.ros.org中某个包-校验和不符”的解决方法
    从ROS bag文件中提取图像
    计算机视觉、机器学习相关领域论文和源代码大集合
    使用XV-11激光雷达做hector_slam
    机器人操作系统(ROS)教程22:ROS的3D可视化工具—rviz
    ROS探索总结(三)——ROS新手教程
    bootstrap文件上传C#实现
    .net分流抢票助手
    谷歌浏览器整个网页截图方法
  • 原文地址:https://www.cnblogs.com/kylindai/p/322648.html
Copyright © 2011-2022 走看看