`
周凡杨
  • 浏览: 233257 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

线程协作-Condition介绍

阅读更多

    上一篇文章里讲了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的源码,大致了解到两个要点

  •  它是一个接口
  •   它提供的一系列方法都是用来阻塞或唤醒线程用的。(功能类似JavaObject类的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,此时putnotEmpty发送信号,可以解除任何在take中阻塞的线程。

 

 

二:实际运用

 

我们要打印199个数字,由A线程先打印123,然后由B线程打印456,然后再由A线程打印789. 这道题有很多种解法,现在我们使用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

  

  

1
1
分享到:
评论

相关推荐

    Java多线程-多线程知识点总结和企业真题

    - **题8**:如何使用`Condition`对象实现线程间的协作? - 使用`ReentrantLock`的`newCondition()`方法创建`Condition`对象,然后使用`await()`和`signal()`方法实现线程间的等待和通知。 5. **死锁** - **题1**...

    第20章 Part3 多线程互斥与协作.pdf

    ### 第20章 Part3:多线程互斥与协作 #### 一、互斥(Mutual Exclusion) 互斥是指在线程编程中确保多个线程不会同时访问同一资源的技术。这种技术非常重要,因为如果不加以控制,多个线程对共享资源的并发访问...

    Python线程协作threading.Condition实现过程解析

    在Python的多线程编程中,`threading.Condition`是一个重要的工具,用于实现线程间的协作和同步。本文将深入解析`threading.Condition`的工作原理和实现过程,并通过一个简单的男女对话示例来阐述其使用方法。 `...

    Java多线程-线程间的通信

    等待唤醒机制是一种用于线程间协作的机制。它允许一个线程等待特定条件发生(通过调用`wait()`方法),并在条件满足时由其他线程唤醒(通过调用`notify()`或`notifyAll()`方法)。 - **`wait()`**:使当前线程进入...

    Java多线程运算集合

    - 是一种经典的线程协作模型,用来解决生产者和消费者之间的数据交换问题。 - 生产者负责生产数据,消费者负责消费数据,两者通过共享缓冲区进行通信。 #### 十、Java线程:并发协作-死锁 - **死锁**: - 发生...

    python多线程-threading模块.docx

    ### Python多线程-threaning模块详解 ...无论是简单的线程创建,还是复杂的线程同步和协作问题,`threading`模块都能提供有效的解决方案。熟练掌握`threading`模块的使用方法对于编写高性能的Python应用程序至关重要。

    安全的编写多线程的_Java_应用程序

    本文将详细介绍如何安全地编写多线程Java应用程序,避免最常见的问题,并提供一些实用的解决方案。 #### 二、多线程基础 **1. 线程概念** - **定义**: 线程是程序执行流的最小单元,是进程内的一个执行实体。一个...

    Java-for-thread.zip_java 线程

    - **管程(Monitor)**:通过`wait()`, `notify()`和`notifyAll()`方法实现线程间的协作和通信。 - **条件变量(Condition)**:`Lock`接口的实现类提供了条件变量,可以创建多个条件队列,实现更灵活的通信。 6....

    性能之多线程-演示Demo

    这些代码可能涉及了线程的创建、启动、暂停、恢复、终止等操作,以及线程间的通信和协作。例如,使用`join()`方法可以让主线程等待某个子线程结束,或者使用`wait()`和`notify()`(Java)或`Condition`(Python)...

    java并发之线程间通信协作.docx

    在Java并发编程中,线程间通信协作是一个关键的概念,特别是在多线程环境中,如生产者-消费者模型。这个模型中,生产者线程负责生产数据并放入队列,而消费者线程则负责取出并消费这些数据。为了保证数据的安全和...

    Java多线程与线程安全实践-基于Http协议的断点续传.rar

    - **同步机制**:包括`synchronized`关键字、锁(Lock)、条件变量(Condition)等,用于控制多个线程对共享资源的访问,防止数据不一致性。 2. **线程安全**: - **线程不安全**:当多个线程同时访问同一块数据...

    多线程编程之一 介绍+例程

    标题“多线程编程之一 介绍+例程”暗示我们将从基础出发,逐步揭示多线程编程的核心原理,并通过实际的代码示例来辅助理解。 首先,我们需要了解什么是多线程编程。在单线程环境中,程序按照顺序执行任务。而在多...

    多线程之间的线程通信

    3. **条件变量(Condition Variable)**:线程可以等待某个特定条件满足后才继续执行,这通常与锁结合使用,用于实现线程间的协作。 4. **管道(Pipe)**和**套接字(Socket)**:这些是进程间通信(IPC)的方法,也可以...

    Java线程间的通信----生产者消费者模型

    在Java编程中,线程间的通信是多线程编程中的一个重要概念,特别是在处理并发和协作任务时。生产者消费者模型是一种经典的线程同步问题,它模拟了实际生活中的生产过程和消费过程,使得生产者线程可以将数据生产出来...

    Java多线程与线程安全实践-基于Http协议的断点续传毕业设计—(包含完整源码可运行).rar

    - **线程协作**:线程间协作完成文件下载,可能使用`CountDownLatch`或`CyclicBarrier`等同步工具。 - **错误处理**:处理网络中断、服务器错误等情况,支持重新连接和重试下载。 5. **源码分析**: - **服务器...

    java多线程案例——未完成

    - `wait()`, `notify()`, `notifyAll()`:在同步块内使用,用于线程间的通信和协作。 - `Lock`和`Condition`:更灵活的锁机制,提供公平锁、非公平锁、读写锁等。 4. **死锁**: 当两个或更多线程互相等待对方...

    线程异步工作,当一个线程结束时异步通知另一线程

    在多线程编程中,线程间的协作是关键任务之一,尤其当需要一个线程在完成特定工作后通知另一个线程继续执行时。这个过程通常涉及到线程同步和异步的概念。本文将深入探讨线程异步工作以及如何在C++中实现一个线程在...

Global site tag (gtag.js) - Google Analytics