写点什么

Java 多线程系列 8:JDK 中的管程实现之条件变量

作者:BigBang!
  • 2023-12-22
    广东
  • 本文字数:1432 字

    阅读完需:约 5 分钟

Java多线程系列8:JDK中的管程实现之条件变量

管程包括锁和条件变量,他们组合在一起解决了多线程互斥和协同的问题。上篇文章介绍了 JDK 包中的 Lock 接口以及主要的加锁方法,这篇文章介绍如何使用条件变量来解决多个线程协同的问题。和 Java 语言提供的由 synchronized/wait/nofity/notifyAll 组合实现的管程相比,JDK 包中实现的管程条件变量更加灵活和强大。


JDK 包的 Lock 接口有一个方法:newCondition(),这个方法返回一个条件变量(Condition)对象。与 synchronized 只能拥有一个条件变量相比,Lock 对象可以拥有多个条件变量,以实现复杂的状态控制。例如在生产者和消费者模式中,可以用两个条件变量(Full 和 Empty)来实现生产者和消费者之间的协同,具体做法就是通过 Condition 提供的 await/signal/signalAll 来实现。


Condition 提供的 await/signal/signalAll 和 Object 提供的 wait/notify/nofityAll 实现的功能是一样的,但千万不要用错。如果你用的是 JDK 包的 Lock,就不能调用 wait/nofity/nofityAll。


下面我们来看一个简单的例子:

package demo;
import java.util.Random;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;
public class DummyFuture { private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition();
private Integer result = null;
private void received(Integer result) { lock.lock(); try { this.result = result; condition.signalAll(); } finally { lock.unlock(); }
}
private Integer getResult() { try { lock.lock(); while (result == null) { condition.await(); //等待有人在未来给一个结果值,否则一直等待 } return result; } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); }
}

public static void main(String[] args) throws InterruptedException { DummyFuture dummyFuture = new DummyFuture();
Thread executor = new Thread(() -> { try { Thread.sleep(1000); dummyFuture.received(new Random().nextInt(100)); } catch (InterruptedException e) { throw new RuntimeException(e); } }); executor.start(); System.out.println(dummyFuture.getResult()); executor.join(); }}

复制代码


这个例子演示了如何基于条件变量来在两个线程间进行协同。主线程尝试获取一个值,获取不到则进入的等待。未来某个时候有别的线程来设置这个值,然后通知主线程,主线程于是被唤醒拿到结果。还有一个小细节,在通知主线程时,用了 condiation.signalAll()方法,记住:任何时候用 signalAll()方法总不会错,避免出现线程饥饿的情况。


同样的,我们也可以用类似的方式来实现生产者-消费者模式,当然你需要两个条件变量。具体这里就不给代码了,大家可以自行尝试一下。


上面的示例代码实际上是实现 Future 和线程池的一种思路,不过幸运的是,JDK 并发包中早就实现了功能非常强大的 Future 和 ThreadPoolExecutor,后继我们将继续介绍它们的用法和设计思路。

发布于: 刚刚阅读数: 3
用户头像

BigBang!

关注

宁静致远,快乐随行,知行合一,得大自在! 2008-10-08 加入

一个程序员,一名架构师,一位技术管理人......

评论

发布
暂无评论
Java多线程系列8:JDK中的管程实现之条件变量_Java多线程_BigBang!_InfoQ写作社区