上一篇讲述了并发包下的Lock,Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇之上,使用Lock如何处理线程通信。
那么引入本篇的主角,Condition,Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。下面将之前写过的一个线程通信的例子替换成用Condition实现(Java线程(三)),代码如下:
- public class ThreadTest2 {
- public static void main(String[] args) {
- final Business business = new Business();
- new Thread(new Runnable() {
- @Override
- public void run() {
- threadExecute(business, "sub");
- }
- }).start();
- threadExecute(business, "main");
- }
- public static void threadExecute(Business business, String threadType) {
- for(int i = 0; i < 100; i++) {
- try {
- if("main".equals(threadType)) {
- business.main(i);
- } else {
- business.sub(i);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- class Business {
- private boolean bool = true;
- private Lock lock = new ReentrantLock();
- private Condition condition = lock.newCondition();
- public /*synchronized*/ void main(int loop) throws InterruptedException {
- lock.lock();
- try {
- while(bool) {
- condition.await();//this.wait();
- }
- for(int i = 0; i < 100; i++) {
- System.out.println("main thread seq of " + i + ", loop of " + loop);
- }
- bool = true;
- condition.signal();//this.notify();
- } finally {
- lock.unlock();
- }
- }
- public /*synchronized*/ void sub(int loop) throws InterruptedException {
- lock.lock();
- try {
- while(!bool) {
- condition.await();//this.wait();
- }
- for(int i = 0; i < 10; i++) {
- System.out.println("sub thread seq of " + i + ", loop of " + loop);
- }
- bool = false;
- condition.signal();//this.notify();
- } finally {
- lock.unlock();
- }
- }
- }
在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。
这样看来,Condition和传统的线程通信没什么区别,Condition的强大之处在于它可以为多个线程间建立不同的Condition,下面引入API中的一段代码,加以说明。
- 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;//如果写索引写到队列的最后一个位置了,那么置为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;//如果读索引读到队列的最后一个位置了,那么置为0
- --count;//个数--
- notFull.signal();//唤醒写线程
- return x;
- } finally {
- lock.unlock();
- }
- }
- }
这是一个处于多线程工作环境下的缓存区,缓存区提供了两个方法,put和take,put是存数据,take是取数据,内部有个缓存队列,具体变量和方法说明见代码,这个缓存区类实现的功能:有多个线程往里面存数据和从里面取数据,其缓存队列(先进先出后进后出)能缓存的最大数值是100,多个线程间是互斥的,当缓存队列中存储的值达到100时,将写线程阻塞,并唤醒读线程,当缓存队列中存储的值为0时,将读线程阻塞,并唤醒写线程,下面分析一下代码的执行过程:
1. 一个写线程执行,调用put方法;
2. 判断count是否为100,显然没有100;
3. 继续执行,存入值;
4. 判断当前写入的索引位置++后,是否和100相等,相等将写入索引值变为0,并将count+1;
5. 仅唤醒读线程阻塞队列中的一个;
6. 一个读线程执行,调用take方法;
7. ……
8. 仅唤醒写线程阻塞队列中的一个。
这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间。
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7481142,转载请注明。
相关推荐
#### 九、Java线程:并发协作-生产者消费者模型 - **生产者消费者模型**: - 是一种经典的线程协作模型,用来解决生产者和消费者之间的数据交换问题。 - 生产者负责生产数据,消费者负责消费数据,两者通过共享...
在Java编程中,线程间的通信是多线程编程中的一个重要概念,特别是在处理并发和协作任务时。生产者消费者模型是一种经典的线程同步问题,它模拟了实际生活中的生产过程和消费过程,使得生产者线程可以将数据生产出来...
在Java多线程编程中,线程间的通信是非常重要的概念,用于协调多个并发执行的任务。线程的状态转换是理解线程通信的基础,主要包括四个...因此,理解并熟练掌握Java中的线程通信机制对于编写高效的多线程程序至关重要。
#### 九、Java线程:并发协作 - **生产者消费者模型** 一种经典的并发模式,其中“生产者”线程负责生产数据,“消费者”线程负责消费数据。这种模型通常通过队列结构来实现。 - **死锁** 死锁发生在多个线程...
在Java编程中,多线程通信是一个至关重要的概念,特别是在设计高效的并发应用程序时。这个"Java线程通信示例源代码"很可能包含了演示如何在不同线程之间共享数据和协调执行顺序的实例。线程通信主要涉及两个核心概念...
### Java多线程知识点解析 #### 一、Java多线程概述 Java作为一种现代编程语言,内置了对多线程的支持。多线程允许应用程序同时处理多个任务,从而提高程序的响应性和整体性能。在多线程环境中,一个程序可以包含...
本文将深入探讨Java线程的相关知识点。 1. **线程的概念与原理**: - 线程是操作系统调度的基本单位,每个线程拥有自己的程序计数器、寄存器和栈,但共享同一块内存区域。 - 在Java中,可以通过继承Thread类或...
### Java多线程—线程间的通信 #### 一、线程间的通信 ##### (1)为什么要处理线程间的通信? 在多线程环境中,不同的线程可能需要协同工作来完成一项任务。例如,一个线程负责生产数据,另一个线程负责消费这些...
- Condition接口:与Lock配合使用,提供了更灵活的线程通信方式。 6. **线程池**: - ExecutorService:Java并发包提供的线程池接口,用于管理线程生命周期,减少线程创建销毁的开销。 - ThreadPoolExecutor:...
Java线程是编程中不可或缺的一部分,特别是在开发大型的、高并发的应用时。下面将详细讨论与Java线程相关的知识点。 1. **线程与进程**: - **线程**是程序的执行单元,它在进程的上下文中运行,一个进程中可以有...
4. **线程通信** - wait()、notify()和notifyAll():这些方法用于线程间的通信,通常配合synchronized使用。一个线程调用wait()会释放锁并等待,而notify()或notifyAll()则唤醒等待的线程。 - Condition接口:在...
- **线程通信**:`BlockingQueue`和`Condition`可以实现线程间的通信,协调执行顺序。 2. **线程安全**: - **线程不安全问题**:包括数据竞争、死锁、活锁和饥饿等问题,这些问题可能导致程序行为不可预测或性能...
5. **线程通信**:介绍wait()、notify()和notifyAll()方法,以及条件变量(Condition)的概念。 6. **原子操作与volatile**:分析AtomicInteger、AtomicLong等原子类的原理,以及volatile关键字的作用和使用场景。 ...
- **线程间通信**:wait()、notify()、notifyAll()。 - **并发工具类**:ExecutorService、Callable、Future、CountDownLatch、CyclicBarrier。 #### 4. 输入/输出流 - **字节流**:InputStream、OutputStream。 - ...
一个进程中的多个线程共享同一份内存空间,使得通信更加高效。 - **为什么要使用多线程**: - 提高程序的执行效率,充分利用多核处理器资源。 - 改善用户体验,如在处理耗时操作时不阻塞用户界面。 - **多线程...
在Java编程中,多线程和线程安全是核心概念,尤其在开发高效、响应迅速的应用时更是不可或缺。本实践项目以HTTP协议为基础,探讨如何实现断点续传功能,这是在网络上传输大文件时非常实用的一个特性。下面将详细阐述...
Java线程有10个优先级,`MIN_PRIORITY`(1),`NORM_PRIORITY`(5)和`MAX_PRIORITY`(10)。较高的优先级并不意味着线程一定先执行,而是增加了获取CPU资源的概率。 5. **守护线程(Daemon)** 守护线程是支持...
6. **线程通信** - **题1**:`wait()`和`notify()`方法的作用是什么? - `wait()`使当前线程进入等待状态,`notify()`唤醒一个等待线程。 - **题2**:如何使用`wait()`和`notify()`方法实现生产者消费者模型? -...
在Java编程中,多线程(Multithreading)是实现并发执行任务的重要机制...总之,Java的多线程特性为编写高效、响应性强的程序提供了强大的支持。正确理解和运用这些概念,可以帮助开发者设计出更加健壮和高性能的应用。