上一篇文章里讲了java.util.concurrent.locks 包下的Lock,以及简单使用的例子,这一篇我们要继续介绍java.util.concurrent.locks包下的类文件,它就是Condition
一:源码解读
package java.util.concurrent.locks; import java.util.concurrent.*; import java.util.Date; /** * Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象, * 以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set) * 其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用 */ public interface Condition { /** * 造成当前线程在接到信号或被中断之前一直处于等待状态。 */ void await() throws InterruptedException; /** * 造成当前线程在接到信号之前一直处于等待状态。 */ void awaitUninterruptibly(); /** * 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。 */ long awaitNanos(long nanosTimeout) throws InterruptedException; /** * 造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。 */ boolean await(long time, TimeUnit unit) throws InterruptedException; /** * 造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。 */ boolean awaitUntil(Date deadline) throws InterruptedException; /** * 唤醒一个等待线程。 */ void signal(); /** * 唤醒所有等待线程。 */ void signalAll(); }
说明:通过查看Condition的源码,大致了解到两个要点
- 它是一个接口
- 它提供的一系列方法都是用来阻塞或唤醒线程用的。(功能类似Java中Object类的wait(),notify()和notifyAll()方法)
JDK的官方解释如下:
条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。 Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
在JDK的源码中,还提供了一个关于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{ while(count == items.length){ notFull.await(); //造成当前线程在接到信号或被中断之前一直处于等待状态。 } items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; 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();//解锁 } } }
这里使用了ReentrantLock锁和Condition对象给出了有界缓存的实现,即使用Condition,分别为notFull和 notEmpty。当缓存为空时,take将阻塞并等待notEmpty,此时put向notEmpty发送信号,可以解除任何在take中阻塞的线程。
二:实际运用
我们要打印1到9这9个数字,由A线程先打印1,2,3,然后由B线程打印4,5,6,然后再由A线程打印7,8,9. 这道题有很多种解法,现在我们使用Condition来做这道题。
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class PrintDemo { //申请锁 final Lock lock = new ReentrantLock(); final Condition conditionA = lock.newCondition(); final Condition conditionB = lock.newCondition(); private String worker = "A"; //默认是A先工作 private int endNum = 9; private int i = 1; public static void main(String[] args){ PrintDemo pd = new PrintDemo(); pd.print(); } public void print(){ new Thread(new Runnable() { @Override public void run() { lock.lock();//加锁 try{ while(i<endNum){ while(!worker.equals("A")){ conditionA.await(); //如果worker不是A,表示A不需要工作,则处于休眠等待 } System.out.println(i + "--" + Thread.currentThread().getName()); if(i%3==0){ worker = "B"; conditionB.signal(); } i++; } System.out.println(i + "--" + Thread.currentThread().getName()); }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock();//解锁 } } }, "threadA").start(); new Thread(new Runnable() { @Override public void run() { lock.lock();//加锁 try{ while(i<endNum){ while(!worker.equals("B")){ conditionB.await(); //如果worker不是B,表示B不需要工作,则处于休眠等待 } System.out.println(i + "--" + Thread.currentThread().getName()); if(i%3==0){ worker = "A"; conditionA.signal(); } i++; } }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock();//解锁 } } }, "threadB").start(); } }
运行结果:
1--threadA
2--threadA
3--threadA
4--threadB
5--threadB
6--threadB
7--threadA
8--threadA
9--threadA
通过使用Condition,有效了使线程A和线程B进行协作工作,A打印完1、2、3后,B打印4、5、6,然后A再打印7、8、9.其实这里只是简单的使用例子,真正的使用环境并不是打印字母这么简单。
在这里,我想抛出一个问题:为什么一个Lock可以创建两个Condition,它是怎么实现的?
参考资料:
http://blog.csdn.net/ghsau/article/details/7481142
http://ifeve.com/understand-condition/
http://www.th7.cn/Program/java/201308/147915.shtml
http://outofmemory.cn/java/java.util.concurrent/lock-reentrantlock-condition
相关推荐
- **题8**:如何使用`Condition`对象实现线程间的协作? - 使用`ReentrantLock`的`newCondition()`方法创建`Condition`对象,然后使用`await()`和`signal()`方法实现线程间的等待和通知。 5. **死锁** - **题1**...
### 第20章 Part3:多线程互斥与协作 #### 一、互斥(Mutual Exclusion) 互斥是指在线程编程中确保多个线程不会同时访问同一资源的技术。这种技术非常重要,因为如果不加以控制,多个线程对共享资源的并发访问...
在Python的多线程编程中,`threading.Condition`是一个重要的工具,用于实现线程间的协作和同步。本文将深入解析`threading.Condition`的工作原理和实现过程,并通过一个简单的男女对话示例来阐述其使用方法。 `...
等待唤醒机制是一种用于线程间协作的机制。它允许一个线程等待特定条件发生(通过调用`wait()`方法),并在条件满足时由其他线程唤醒(通过调用`notify()`或`notifyAll()`方法)。 - **`wait()`**:使当前线程进入...
- 是一种经典的线程协作模型,用来解决生产者和消费者之间的数据交换问题。 - 生产者负责生产数据,消费者负责消费数据,两者通过共享缓冲区进行通信。 #### 十、Java线程:并发协作-死锁 - **死锁**: - 发生...
### Python多线程-threaning模块详解 ...无论是简单的线程创建,还是复杂的线程同步和协作问题,`threading`模块都能提供有效的解决方案。熟练掌握`threading`模块的使用方法对于编写高性能的Python应用程序至关重要。
本文将详细介绍如何安全地编写多线程Java应用程序,避免最常见的问题,并提供一些实用的解决方案。 #### 二、多线程基础 **1. 线程概念** - **定义**: 线程是程序执行流的最小单元,是进程内的一个执行实体。一个...
- **管程(Monitor)**:通过`wait()`, `notify()`和`notifyAll()`方法实现线程间的协作和通信。 - **条件变量(Condition)**:`Lock`接口的实现类提供了条件变量,可以创建多个条件队列,实现更灵活的通信。 6....
这些代码可能涉及了线程的创建、启动、暂停、恢复、终止等操作,以及线程间的通信和协作。例如,使用`join()`方法可以让主线程等待某个子线程结束,或者使用`wait()`和`notify()`(Java)或`Condition`(Python)...
在Java并发编程中,线程间通信协作是一个关键的概念,特别是在多线程环境中,如生产者-消费者模型。这个模型中,生产者线程负责生产数据并放入队列,而消费者线程则负责取出并消费这些数据。为了保证数据的安全和...
- **同步机制**:包括`synchronized`关键字、锁(Lock)、条件变量(Condition)等,用于控制多个线程对共享资源的访问,防止数据不一致性。 2. **线程安全**: - **线程不安全**:当多个线程同时访问同一块数据...
标题“多线程编程之一 介绍+例程”暗示我们将从基础出发,逐步揭示多线程编程的核心原理,并通过实际的代码示例来辅助理解。 首先,我们需要了解什么是多线程编程。在单线程环境中,程序按照顺序执行任务。而在多...
3. **条件变量(Condition Variable)**:线程可以等待某个特定条件满足后才继续执行,这通常与锁结合使用,用于实现线程间的协作。 4. **管道(Pipe)**和**套接字(Socket)**:这些是进程间通信(IPC)的方法,也可以...
在Java编程中,线程间的通信是多线程编程中的一个重要概念,特别是在处理并发和协作任务时。生产者消费者模型是一种经典的线程同步问题,它模拟了实际生活中的生产过程和消费过程,使得生产者线程可以将数据生产出来...
- **线程协作**:线程间协作完成文件下载,可能使用`CountDownLatch`或`CyclicBarrier`等同步工具。 - **错误处理**:处理网络中断、服务器错误等情况,支持重新连接和重试下载。 5. **源码分析**: - **服务器...
- `wait()`, `notify()`, `notifyAll()`:在同步块内使用,用于线程间的通信和协作。 - `Lock`和`Condition`:更灵活的锁机制,提供公平锁、非公平锁、读写锁等。 4. **死锁**: 当两个或更多线程互相等待对方...
在多线程编程中,线程间的协作是关键任务之一,尤其当需要一个线程在完成特定工作后通知另一个线程继续执行时。这个过程通常涉及到线程同步和异步的概念。本文将深入探讨线程异步工作以及如何在C++中实现一个线程在...