一个线程进入临界区,却发现它必须等待某个条件满足后才能执行,则要使用一个条件变量来管理那些已获得锁却不能开始执行有用的工作的线程。
看个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
// 可重入的互斥锁
final Lock lock = new ReentrantLock();
// 表示"缓冲区没满"条件
final Condition notFull = lock.newCondition();
// 表示"缓冲区非空"条件
final Condition notEmpty = lock.newCondition();
// 存储空间
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
//锁住原子操作单元
lock.lock();
try {
/*
* 发现缓冲区已满,则阻塞当前线程,放弃锁;
* 以便其它线程能向缓冲区中take数据。
*
* 一旦一个线程调用了await方法,它就进入等待该条件集,
* 当锁可获得时,线程不能立刻解除阻塞,
* 它维护阻塞状态直到另一个线程调用同一个条件上的
* signal(唤醒其中的一个等待线程)方法或signalAll(唤醒所有等待线程)方法
*
* 一旦线程被唤醒,从而有一个线程将获得锁并从它被阻塞的地方继续执行。
* 此时,线程应该再次测试条件,因为现在还不能确定条件一定已经满足。
* signal/signalAll方法仅仅是通知等待的线程:现在条件有可能已经满足了,值得再去测试一下条件。
* 因此,为await的调用应该总是在while等循环中。
*
*/
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
/*
* 特别注意:对signalAll的调用不会立即激活等待线程。它只是解除等待线程的阻塞状态。
* 这样这些线程就可以在当前线程退出同步方法后,通过竞争获得对对象的访问。
*
* signal则是随机解除等待集中的某个线程的阻塞状态,如果被随机选中的线程发现自己还是
* 无法运行,它会再次阻塞,如果没有任何其它线程再次调用signal方法,则系统死锁。
*/
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
int threadCount = 5;
BoundedBuffer b = new BoundedBuffer();
for(int i=0;i<threadCount;i++)
{
if(i%2 == 0)
new PutThread(b).start();
new TakeThread(b).start();
}
}
public static class PutThread extends Thread
{
private BoundedBuffer b;
private int put = 0;
public PutThread(BoundedBuffer b)
{
this.b = b;
}
@Override
public void run() {
try {
String data = null;
while(true)
{
data = "data" + (++put);
System.out.println(data);
b.put(data);
Thread.sleep(100);
}
} catch (InterruptedException e) {
//e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
public static class TakeThread extends Thread
{
private BoundedBuffer b;
public TakeThread(BoundedBuffer b)
{
this.b = b;
}
@Override
public void run() {
try {
while(true)
{
System.out.println(b.take());
}
} catch (InterruptedException e) {
//e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}
总结lock和condition的关键点:
1.锁用来保护代码片断,任何时刻只允许一个线程执行被保护的代码。
2.锁可以管理试图进入被保护代码段的线程。
3.锁可以拥有一个或多个相关的条件对象。
4.每个条件对象管理那些已进入被保护代码段但还不能运行的线程。
分享到:
相关推荐
在多线程编程中,条件变量(Condition Variables)是一种重要的同步机制,用于线程间的通信和协调。条件变量允许线程在满足特定条件时挂起执行,等待其他线程改变状态,然后再唤醒继续执行。这种方式使得线程可以...
条件变量(Condition Variable)则是另一个重要的同步机制,它允许线程在满足特定条件时被唤醒或阻塞。下面,我们将详细解释互斥锁和条件变量的工作机制、使用场景和注意事项。 互斥锁(Mutex) 互斥锁是最基本的...
本示例着重讲解如何利用C++标准库中的互斥锁(mutex)和条件变量(condition variable)进行线程同步,并实现跨平台的封装。这些工具是多线程编程中的关键组成部分,用于确保共享资源的安全访问。 首先,让我们了解...
Java通过java.util.concurrent.locks包中的Condition接口提供了条件变量的实现。本文将详细介绍Condition接口的工作原理、使用方法以及如何在实际项目中应用它。 Condition接口是Java并发编程中实现等待/通知模式的...
条件变量(Condition Variable)则是为了解决这一问题而引入的。条件变量允许线程在资源不满足其工作条件时,主动释放锁并进入等待状态。其他线程可以在适当的时候唤醒这些等待的线程。条件变量通常与互斥锁一起使用...
2. **条件变量(Condition Variable)**: 条件变量允许进程在特定条件满足时才继续执行。它与互斥锁配合使用,可以在等待某个条件时,释放锁并进入休眠状态,条件改变时,由其他进程唤醒。在C语言中,`pthread_...
本示例中提到的“linux无亲缘关系进程间通信”着重讲解了如何利用互斥锁(Mutex)、条件变量(Condition Variable)以及共享内存(Shared Memory)这三种机制来实现非父子进程间的同步通信。 1. **互斥锁**:互斥锁...
条件变量通常与互斥锁(mutex)一起使用,以避免竞争条件(Race Condition)和确保线程间的同步。本篇讲解将详细介绍Linux条件变量的基本概念、使用方法及其相关函数。 首先,条件变量是一种线程间通信的同步机制,...
条件变量(Condition Variable): 条件变量允许线程在特定条件满足时才继续执行。在实现线程池时,可能使用条件变量来通知线程何时有新任务到来或者线程池是否已关闭。线程可以等待条件变量,只有当其他线程改变...
条件变量(Condition Variables)是线程同步的一种工具,它允许线程在满足特定条件时等待,只有当其他线程改变了这个条件,等待的线程才会被唤醒。条件变量与互斥锁(Mutexes)配合使用,可以实现更灵活的线程同步...
std::condition_variable 是 C++11 标准中 <condition_variable> 头文件里的一个类,用于实现条件变量的功能。条件变量是一种同步机制,允许线程在某个条件下等待或被唤醒。 std::condition_variable 的主要功能是...
在多线程编程中,线程间的通信是非常重要的,条件变量(Condition Variables)是POSIX线程(pthread)库提供的一种同步机制,它允许线程在特定条件满足时才能继续执行。在Linux系统编程中,条件变量通常与互斥锁...
Python中的线程条件变量(Condition)是多线程编程中的一种同步机制,它允许线程在特定条件下等待,直到其他线程改变这个条件并通知它们。条件变量通常与锁一起使用,确保在进行条件检查和操作时数据的一致性。 在...
在多线程编程中,条件变量(Condition Variables)是一个重要的同步机制,用于线程间的通信和协调。条件变量允许线程等待某个特定条件的发生,并在条件满足时被其他线程唤醒。然而,条件变量存在一个特性,即虚假...
Java提供了多种同步机制,如synchronized关键字、Lock接口(包括ReentrantLock)、Semaphore信号量、Condition条件变量等。synchronized可以用于修饰方法或代码块,实现互斥访问;Lock接口提供了更细粒度的控制,...
在 Nachos 操作系统中,条件变量是通过 Condition 类来实现的。 Condition 类中有三个主要的方法:Wait()、Signal() 和 BroadCast()。Wait() 方法用于线程等待条件变量的出现,当前线程将释放锁并进入睡眠状态。...
二、条件变量(Condition Variable) 条件变量是多线程编程中另一个重要的同步机制,它用于解决多线程之间的状态同步问题。C++标准库提供了std::condition_variable类来实现条件变量的功能。 在上面的代码中,我们...
Condition_Variable 的构造函数中初始化了条件变量,并在析构函数中销毁了条件变量。 Condition_Variable 的 wait() 函数使用 pthread_cond_wait() 函数来实现等待操作,而 notify_one() 和 notify_all() 函数使用...
条件变量(Condition)是Lock的一个扩展,它允许线程等待特定条件满足后再继续执行。每个Lock对象可以有多个条件变量。例如,Condition接口提供了以下方法: 1. await():使当前线程进入等待状态,直到被信号...