博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java线程:条件变量 lock
阅读量:5903 次
发布时间:2019-06-19

本文共 3833 字,大约阅读时间需要 12 分钟。

hot3.png

    条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。
    这里的条件和普通意义上的条件表达式有着天壤之别。条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
    条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。
     而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。有关Condition接口的API可以具体参考JavaAPI文档。
条件变量比较抽象,原因是他不是自然语言中的条件概念,而是程序控制的一种手段。
下面以一个银行存取款的模拟程序为例来揭盖Java多线程条件变量的神秘面纱:

有一个账户,多个用户(线程)在同时操作这个账户,有的存款有的取款,存款随便存,取款有限制,不能透支,任何试图透支的操作都将等待里面有足够存款才执行操作。  

    如果程序不使用synchronized关键字来保证同步,而直接用lock.那么系统中不存在隐式的同步监视器,就不能使用wait,notify,notifyAll方法进行线程通信了.但使用Lock对象来保证同步时,Java提供了一个Condition类来保持协调,使用Condition可以让那些已经得到Lock对象但无法继续执行的线程释放Lock对象,Condition对象也可以唤醒其他等待的线程.这情况下,Lock替代了同步方法或同步代码块,Condition替代了同步监视器的功能.

Condition实例绑定在Lock对象上,要获得需要调用Lock对象的newCondition方法.有3个方法:

  1. await():类似于隐式同步监视器上的wait方法.该await方法有更多的重载方法.
  2. signal():任意唤醒一个Lock对象上等待的单个线程.只有当前线程放弃对该Lock对象的锁定后(使用await()方法),才可以自行被唤醒的线程.
  3. signalAll():唤醒所有等待线程。

package com.thread.lock;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class MyCount {	private String id; // 账号	private int cash; // 账户余额	private Lock lock = new ReentrantLock(); // 账户锁	private Condition _save = lock.newCondition(); // 存款条件	private Condition _draw = lock.newCondition(); // 取款条件	MyCount(String id, int cash) {		this.id = id;		this.cash = cash;	}	/**	 * 存款	 * 	 * @param name	 *            存款人姓名	 * @param cash	 *            存款金额	 */	public void saving(String name, int saveCash) {		lock.lock();		if (saveCash > 0) {			cash += saveCash;			System.out.println(name + " 存款 " + saveCash + ",当前余额为" + cash);		}		_draw.signalAll(); // 唤醒所有等待线程。		lock.unlock(); // 释放锁	}	/**	 * 取款	 * 	 * @param name	 *            取款人姓名	 * @param cash	 *            取款金额	 */	public void drawing(String name, int saveCash) {		lock.lock();		try {			if (cash < saveCash) {				_draw.await();				// 阻塞取款操作			} else {				cash -= saveCash;// 取款				System.out.println(name + " 取款 " + saveCash + ",当前余额为" + cash);			}			_save.signalAll(); // 唤醒所有存款操作		} catch (InterruptedException e) {			System.out.println(name + " 取款超额了" + " 取款金额为:" + saveCash);			// TODO Auto-generated catch block			// e.printStackTrace();		} finally {			lock.unlock();		}	}}class DrawThread extends Thread {	private String name; // 操作人	private MyCount myCount; // 账户	private int saveCash; // 存款金额	DrawThread(String name, MyCount myCount, int saveCash) {		this.name = name;		this.myCount = myCount;		this.saveCash = saveCash;	}	@Override	public void run() {		myCount.drawing(name, saveCash);	}}class SaveThread extends Thread {	private String name; // 操作人	private MyCount myCount; // 账户	private int saveCash; // 存款金额	SaveThread(String name, MyCount myCount, int saveCash) {		this.name = name;		this.myCount = myCount;		this.saveCash = saveCash;	}	@Override	public void run() {		myCount.saving(name, saveCash);	}}package com.thread.lock;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class TestLock {	public void run(){		ExecutorService pool = Executors.newFixedThreadPool(5);		MyCount count = new MyCount("43089183736746383", 1200);		SaveThread save1 =  new SaveThread("张三",count, 200);		SaveThread save2 =  new SaveThread("李四",count, 100);		DrawThread draw1 = new DrawThread("王五", count, 1600);		DrawThread draw2 = new DrawThread("赵六", count, 500);		SaveThread save3 =  new SaveThread("王杰",count, 3000);		pool.execute(save1);		pool.execute(save2);		pool.execute(draw1);		pool.execute(draw2);		pool.execute(save3);		pool.shutdownNow();	}    public static void main(String[] args) {		new TestLock().run();	}}

转载于:https://my.oschina.net/jielucky/blog/156827

你可能感兴趣的文章
ubuntu下安装libxml2
查看>>
nginx_lua_waf安装测试
查看>>
WinForm窗体缩放动画
查看>>
JQuery入门(2)
查看>>
linux文件描述符
查看>>
传值引用和调用引用的区别
查看>>
hyper-v 无线网连接
查看>>
Python3.7.1学习(六)RabbitMQ在Windows环境下的安装
查看>>
Windows下memcached的安装配置
查看>>
ubuntu: firefox+flashplay
查看>>
web.xml 中CharacterEncodingFilter类的学习
查看>>
贪吃蛇逻辑代码
查看>>
实现c协程
查看>>
ASP.NET视频教程 手把手教你做企业论坛网站 视频教程
查看>>
[LeetCode] Meeting Rooms II
查看>>
从Swift学习iOS开发的路线指引
查看>>
Scribes:小型文本编辑器,支持远程编辑
查看>>
ssh 安装笔记
查看>>
3-继承
查看>>
海归千千万 为何再无钱学森
查看>>