`

JDK1.5 Condition接口

阅读更多

Condition Object 监视器方法(waitnotify notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

条件(也称为条件队列或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其等待)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁定与该条件相关联。等待提供一个条件的主要属性是:以原子方式释放相关的锁定,并挂起当前线程,就像 Object.wait 做的那样。

Condition 实例实质上被绑定到一个锁定上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

作为一个示例,假定有一个绑定的缓冲区,它支持 put take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。

 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();

     }

   }

 }

ArrayBlockingQueue类提供了这项功能,因此没有理由去实现这个示例类。)

Condition 实现可以提供不同于 Object 监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁定。如果某个实现提供了这样特殊的语义,则该实现必须记录这些语义。

注意,Condition 实例只是一些普通的对象,它们自身可以用作 synchronized 语句中的目标,并且可以调用自己的 wait notification 监视器方法。获取 Condition 实例的监视器锁定或者使用其监视器方法,与获取和该 Condition 相关的 Lock 或使用其 waiting signalling 方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition 实例。

 

实例:

package com.bijian.thread;

public class SaveThread extends Thread {

	private String name; // 操作人
	private MyCount myCount; // 账户
	private int x; // 存款金额

	public SaveThread(String name, MyCount myCount, int x) {
		this.name = name;
		this.myCount = myCount;
		this.x = x;
	}

	public void run() {
		myCount.saving(x, name);
	}
}

 

package com.bijian.thread;

public class DrawThread extends Thread {

	private String name; // 操作人
	private MyCount myCount; // 账户
	private int x; // 存款金额

	DrawThread(String name, MyCount myCount, int x) {
		this.name = name;
		this.myCount = myCount;
		this.x = x;
	}

	public void run() {
		myCount.drawing(x, name);
	}
}

 

package com.bijian.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyCount {

	private String oid; // 账号
	private int cash; // 账户余额
	private Lock lock = new ReentrantLock(); // 账户锁
	private Condition _save = lock.newCondition(); // 存款条件
	private Condition _draw = lock.newCondition(); // 取款条件

	MyCount(String oid, int cash) {
		this.oid = oid;
		this.cash = cash;
	}

	public void saving(int x, String name) {
		lock.lock(); // 获取锁
		try {
			if (x > 0) {
				cash += x; // 存款
				System.out.println(name + "存款" + x + ",当前余额为" + cash);
			}
			_draw.signalAll(); // 唤醒所有等待线程。
		} finally {
			lock.unlock();
		}
	}

	public void drawing(int x, String name) {
		lock.lock(); // 获取锁
		try {
			if (cash - x < 0) {
				_draw.await(); // 阻塞取款操作
			} 
			cash -= x; // 取款
			System.out.println(name + "取款" + x + ",当前余额为" + cash);
			
			_save.signalAll(); // 唤醒所有存款操作
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock(); // 释放锁
		}
	}
}

 

package com.bijian.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

	public static void main(String[] args) {
		
		//创建并发访问的账户
		MyCount myCount = new MyCount("95599200901215522", 10000);
		//创建一个线程池
		ExecutorService pool = Executors.newFixedThreadPool(2);
		Thread t1 = new SaveThread("张三", myCount, 2000);
		Thread t2 = new SaveThread("李四", myCount, 3600);
		Thread t3 = new DrawThread("王五", myCount, 2700);
		Thread t4 = new SaveThread("老张", myCount, 600);
		Thread t5 = new DrawThread("老牛", myCount, 1300);
		Thread t6 = new DrawThread("胖子", myCount, 800);
		//执行各个线程
		pool.execute(t1);
		pool.execute(t2);
		pool.execute(t3);
		pool.execute(t6);
		pool.execute(t5);
		pool.execute(t4);
		//关闭线程池
		pool.shutdown();
	}
}

 

运行结果:
张三存款2000,当前余额为12000
李四存款3600,当前余额为15600
王五取款2700,当前余额为12900
胖子取款800,当前余额为12100
老张存款600,当前余额为12700
老牛取款1300,当前余额为11400

 

 

分享到:
评论

相关推荐

    Java JDK1.5 生产消费者模式解决方案

    在JDK 1.5及以后的版本中,Java引入了`java.util.concurrent`包,其中包含了一些强大的并发工具类,如`Lock`接口和`Condition`接口,这些工具大大提升了生产者消费者模式的实现效率和线程安全性。 生产者消费者模式...

    backport-util-concurrent(2.2 /3.1)

    - Condition接口提供了等待/通知机制,允许更精确的线程同步。每个Lock实例可以有多个Condition实例,从而可以实现不同的等待集合。 2. **Phaser** - 在3.1版本中,backport-util-concurrent引入了Phaser,这是一...

    JDK_API_1_7_zh_CN.zip

    9. **并发工具类**:JDK 1.5引入了丰富的并发工具类,如`java.util.concurrent.locks`包中的`ReentrantLock`和`Condition`,提供了更高级的锁机制。 10. **Swing GUI**:虽然在`javax.swing`包中的Swing组件已经...

    java中的Lock类和Condition类.docx

    - Condition接口允许我们创建和管理线程等待队列。每个Lock实例都可以创建一个或多个Condition实例,每个Condition对应一个等待队列。 - `await()`: 当前线程调用此方法后,会被阻塞并从当前条件队列中移除,直到...

    经典Java多线程与并发库高级应用

    例如,Condition接口提供了与Object的wait/notify等效的机制,但功能更加丰富。Semaphere同步工具可以控制通过数量有限的许可。CyclicBarrier可以实现一组线程互相等待直到某个事件发生。CountDownLatch用于一个线程...

    ConditionVariablesJAVA多线程[定义].pdf

    在Java中,从JDK 1.5版本开始,引入了java.util.concurrent.locks.Condition接口,它与java.util.concurrent.locks.Lock接口一起使用,提供了一种灵活的条件变量实现。 首先,我们来理解Lock接口。Lock接口提供了一...

    Android多线程全新讲解[整理].pdf

    Java提供了多种机制来实现这一点,如`synchronized`关键字、`wait()`, `notify()`和`notifyAll()`方法,以及JDK 1.5之后引入的`Lock`和`Condition`接口。`ThreadLocal`类则允许在线程范围内创建独立的数据副本,实现...

    java面试基础知识150题

    - 可以继承其他类(自 JDK 1.5 起无限制)。 - 可以实现接口。 3. **Static Nested Class 和 Inner Class** - Static Nested Class 不依赖于外部类实例,可以独立创建对象。 - Inner Class 必须在外部类实例中...

    关于线程的例子

    本示例将围绕“关于线程的例子”进行深入探讨,结合Eclipse3.3、MyEclipse6以及jdk1.5的软件环境,我们将学习如何在Java中创建、管理及同步线程。 首先,让我们了解线程的基本概念。线程是进程内的一个执行单元,每...

    Android多线程全新讲解.pdf

    JDK 1.5引入了更多的同步工具类,如线程池`ExecutorService`,它允许更有效地管理线程,避免频繁创建和销毁线程带来的开销。`Callable`和`Future`接口提供了获取线程执行结果的能力,而`Future`的`get()`方法可以...

    JAVA-基础多线程

    #### 五、JDK1.5之后的高级同步工具 1. **`ReentrantLock`**: - `ReentrantLock`是Java 1.5之后引入的一个可中断、可轮询、可定时的锁。 - 示例代码: ```java private ReentrantLock lock = new ...

    多线程问题

    例如,在JDK 1.5中引入了新的并发API,并在后续版本中持续改进和优化了这些并发工具,使得Java并发编程变得更加简便和安全。 总之,Java多线程编程极大地增强了程序处理并发任务的能力,但是在享受多线程带来的好处...

    连接sqlserver2008数据库驱动包

    它们是基于Java Database Connectivity (JDBC) API的,JDBC是Java平台上的标准接口,允许Java程序与各种类型的数据库进行通信。 sqljdbc4.jar是针对Java RE 1.6及更高版本的,它包含了对JSR 221(JDBC 4.0)规范的...

    java加强笔记

    #### 一、JDK1.5的新特性 ##### 1. 自动装箱与拆箱 - **自动装箱**:指的是将基本数据类型自动转换成对应的包装类对象。 - 例如:`int i = 1; Integer j = i;` - **自动拆箱**:则是将包装类对象自动转换成基本...

    java的concurrent用法详解

    虽然也有诸如Apache Commons Pool等第三方库提供了部分支持,但这些解决方案相比JDK内置的支持仍然显得不够完善和便捷。 随着Java 1.5的发布,Sun公司(现在是Oracle公司的一部分)引入了`java.util.concurrent`包...

    Maven权威指南 很精典的学习教程,比ANT更好用

    1.5. 一个“项目”的概念模型 1.6. Maven是Ant的另一种选择么? 1.7. 比较Maven和Ant 1.8. 总结 2. 安装和运行Maven 2.1. 验证你的Java安装 2.2. 下载Maven 2.3. 安装Maven 2.3.1. 在Mac OSX上安装Maven ...

    JAVA核心知识点整理(有效)

    1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................

Global site tag (gtag.js) - Google Analytics