AQS应用-Condtion

生活

今天周五,明天加班。
如痴如醉,如梦如醒。

今天开门见山,直接来引入今天的内容。昨天(上一篇)讲到了并发编程开发中非常重要的锁,ReentrantLock,即可重入锁,在这个锁中【其实是在其父接口Lock下】,有个newCondition方法用来创建一个与其锁相关联的条件变量,由于这玩意也是非常之重要,所以单独搞一篇写写,加深记忆。

JAVA中的条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过Lock对象上调用一个newCondition来获取的,这样一个条件变量就和一个锁关联起来了。因此,java中的条件变量只能和锁搭配使用,来控制并发程序对共享资源的竞争。

源码

先来看下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的实现,AQS中的ConditionObject做了什么?

  /** First node of condition queue. */
    private transient Node firstWaiter;
    /** Last node of condition queue. */
   private transient Node lastWaiter;
        可以看到ConditionObject维护了一个等待队列

ConditionObject内部维护了一个等待队列,其实是复用了AQS Node的一个FIFO队列,队列中的每一个Node都是等待在Condition对象上的线程的引用,调用Condition的await方法后,线程释放锁,构造成相应的Node对象进入等待队列,等待被唤醒进入AQS的同步队列参与资源的竞争。

以上的代码细节不深入,可以自己去看,其实都是AQS里的东西,仔细研究过AQS,应该都不会看不明白。
下面直接来看下具体的使用。

案例

Condition常用于生产者消费者模式和阻塞队列的实现。
下面来看下具体的案例。

package test;

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

public class ConditionTest {

	public static void main(String[] args) {
		Account account = new Account();
		CountDownLatch latch = new CountDownLatch(1);
		new Thread(new Action("a", 1000, account, true, latch)).start();
		new Thread(new Action("b", 2000, account, false, latch)).start();
		new Thread(new Action("c", 3000, account, true, latch)).start();
		new Thread(new Action("d", 2500, account, false, latch)).start();
		new Thread(new Action("e", 300, account, true, latch)).start();
		new Thread(new Action("f", 100, account, false, latch)).start();
		new Thread(new Action("g", 500, account, true, latch)).start();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		latch.countDown();


	}
	
	static class Action implements Runnable{
		private String name;
		private int m;
		private Account account;
		private boolean save;
		private CountDownLatch latch;

		@Override
		public void run() {
			try {
				latch.await();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(save) {
				account.save(name,m);
			}else {
				account.draw(name,m);
			}
			
		}

		public Action(String name, int m, Account account, boolean save, CountDownLatch latch) {
			super();
			this.name = name;
			this.m = m;
			this.account = account;
			this.save = save;
			this.latch = latch;
		}

		
		
		
	}
	
	static class Account{
		private ReentrantLock lock = new ReentrantLock();
		
		//存款条件
		private Condition save = lock.newCondition();
		//取款条件
		private Condition draw = lock.newCondition();
		
		//金额  银行卡金额上限4000
		private volatile int money;
		
		public void save(String name,int m) {
			try {
				lock.lock();
				if(m>0) {
					while(money+m>4000) {
						save.await();
						System.out.println(String.format("name:%s,存钱阻塞中", name));

					}
					money+=m;
					System.out.println(String.format("name:%s,存款:%s,余额:%s", name,m,money));
				}
				draw.signalAll();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
		
		public void draw(String name,int m) {
			try {
				lock.lock();
				if(m>0) {
					while(m>money) {
						draw.await();
					System.out.println(String.format("name:%s,取钱阻塞中", name));
					}
					money-=m;
					System.out.println(String.format("name:%s,取款:%s,余额:%s", name,m,money));
					save.signalAll();
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
	}
	
	

}

结果:
name:a,存款:1000,余额:1000
name:c,存款:3000,余额:4000
name:f,取款:100,余额:3900
name:b,取款:2000,余额:1900
name:d,取钱阻塞中
name:e,存钱阻塞中
name:e,存款:300,余额:2200
name:g,存钱阻塞中
name:g,存款:500,余额:2700
name:d,取钱阻塞中
name:d,取款:2500,余额:200

总结

Condition的作用是对锁进行更精确的控制。Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。
不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。

睡觉明天还要加班。。。。
明天看读写锁哦

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/84404981
AQS
今日推荐