condition

任何一个java对象都天然继承于Object类,在线程间实现通信的往往会应用到Object的几个方法,比如wait(),wait(long

timeout),wait(long timeout,int nanos)与notify(),notifyAll()几个方法实现等待/通知机制,同样的,在java Lock体系

下依然会有同样的方法实现等待/通知机制。同样的,在Java Lock体系下依然会有同样的方法实现等待/通知机制。从整体上

来看Object的wait和notify/notifyAll是与对象监视器配合完成线程间的等待/通知机制,而Condition与Lock配合完成等待

通知机制,前者是Java底层级别的,后者是语言级别的,具有更高的可控制性和扩展性。两者除了在使用方式上不同外,在

功能特性上还是有很多的不同:
1.Condition能够支持不响应中断,而通过使用Object方式不支持
2.Condition能够支持多个等待队列(new 多个Condition对象),而Object方式只能支持一个;
3.Condition能够支持超时时间的设置,而Object不支持
参照Object的wait和notify/notifyAll方法,Condition也提供了同样的方法:
针对Object的wait方法
1.void await() throws InterruptedException:当前线程进入等待状态,如果其他线程调用condition的signal或者

signalAll方法并且当前线程获取Lock从await方法返回,如果在等待状态中被中断会抛出被中断异常;
2.long awaitNanos(long nanosTimeout):当前线程进入等待状态直到被通知,中断或者超时;
3.boolean await(long time,TimeUnit unit) throws InterruptedExceeption:同第二种,支持自定义时间单位
4.boolean awaitUntil(Date deadline) throws InterruptedException:当前线程进入等待状态直到被通知,中断或者到了

某个时间
针对Object的notify/notifyAll方法
1.void signal():唤醒一个等待在condition上的线程,将该线程从等待队列中转移到同步队列中,如果在同步队列中能够竞

争到Lock则可以从等待方法中返回。
2.void signalAll():与1的区别在于能够唤醒所有等待在Condition上的线程
2.Condition实现原理分析
2.1等待队列
要想能够深入的掌握condition还是应该知道它的实现原理,现在我们一起来看看
condition 的源码。创建一个condition对象是通过lock.newCondition(),而这个方法实际上是会new 出一个

ConditionObject对象,该类是AQS的一个内部类,有兴趣可以去看看。condition是要和lock配合使用的也就是condition和

Lock是绑定在一起的,而Lock的实现原理又依赖于AQS,自然而然ConditionObject作为AQS的一个内部类无可厚非。我们知道

在锁机制的实现上,AQS内部维护了一个同步队列,如果是独占式锁的话,所有获取锁失败的线程的尾插入到同步队列,同样

的,condition内部也是使用同样的方式,内部维护了一个等待队列,所有调用condition.await方法的线程会加入到等待队

列中,并且线程状态转换为等待状态。另外注意到ConditionObject中有两个成员变量:
这样我们就可以看出来ConditionObject通过持有等待队列的头尾指针来管理等待队列。主要注意的Node类复用了在AQS中的

Node类,其节点状态和相关属性可以去看AQS的实现原理的文章,如果您仔细看完这篇文章对Condition的理解易如反掌,对

lock体系的实现也会有一个质的提升。Node类有这样一个属性:
进一步说明,等待队列是一个单项队列,而在之前说AQS时知道同步队列是一个双向队列。接下来我们用一个demo,通过

debug进去看是不是符合我们的猜想:

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

public class AwaitSignal {

private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
private static volatile boolean flag = false;
/**
 * @param args
 */
public static void main(String[] args) {
	// TODO Auto-generated method stub
	Thread waiter = new Thread(new waiter());
	waiter.start();
	Thread signaler = new Thread(new signaler());
	signaler.start();
}

static class waiter implements Runnable{

	public void run() {
		// TODO Auto-generated method stub
		lock.lock();
    try{
		while(!flag){
			
			System.out.println(Thread.currentThread().getName()+"当前条件不满足等待");
			try {
				condition.await();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(Thread.currentThread().getName()+"接收到通知条件满足");
	}finally{
		lock.unlock();
	}
}

}

static class signaler implements Runnable{

	public void run() {
		// TODO Auto-generated method stub
		lock.lock();
		try{
	    flag = true;
	    condition.signalAll();
		}finally{
			lock.unlock();
		}
	}
	
}

}

输出结果:
Thread-0当前条件不满足等待
Thread-0接收到通知条件满足

开启了两个线程waiter和signaler,waiter线程开始执行的时候由于条件不满足,执行condition.await方法使该线程进入等

待状态同时释放锁,signaler线程获取到锁之后更改条件,并通知所有的等待线程后释放锁。这时,waiter线程获取到锁,

并由于signaler线程更改了条件此时相对于waiter来说条件满足,继续执行。

深入理解
AbstractQueuedSynchronizer(AQS)
1.AQS简介
在同步组件的实现中,AQS是核心部分,同步组件的实现者通过使用AQS提供的模板方法实现同步组件语义,AQS则实现了对同

步状态的管理,以及对阻塞线程进行排队,等待通知等等一些底层的实现处理。AQS则实现了对同步状态的管理,以及对阻塞

线程进行排队,等待通知等等一些底层的实现处理。AQS的核心也包括这些方面:同步队列,独占式锁的获取和释放,共享锁

的获取和释放以及可中断锁,超时等待锁获取这些特性的实现,而这些实际上则是AQS提供出来的模板方法,归纳整理如下:

独占式锁:
void acquire(int arg):独占式获取同步状态,如果获取失败则插入同步队列进行等待
void acquireInterruptibly(int arg):与acquire方法相同,但在同步队列中进行等待的时候可以检测中断;
boolean

tryAcquireNanos(int arg, long nanosTimeout):在acquireInterruptibly基础上增加了超时等待功能,在超时时间内没有

获得同步状态返回false;
boolean release(int arg):释放同步状态,该方法会唤醒在同步队列中的下一个节点

共享式锁:
void acquireShared(int arg):共享式获取同步状态,与独占式的区别在于同一时刻有多个线程获取同步状态;
void

acquireSharedInterruptibly(int arg):在acquireShared方法基础上增加了能响应中断的功能;
boolean

tryAcquireSharedNanos(int arg, long nanosTimeout):在acquireSharedInterruptibly基础上增加了超时等待的功能;
boolean releaseShared(int arg):共享式释放同步状态

要想掌握AQS的底层实现,其实也就是对这些模板方法的逻辑进行学习。在学习这些模板方法之前,我们得首先了解下AQS中

的同步队列是一种什么样的数据结构,因为同步队列是AQS对同步状态的管理的基石。

2.同步队列
当共享资源被某个线程占有,其他请求该资源的线程将会阻塞,从而进入同步队列。就数据结构而言,队列的实现方式无外

乎两者一是通过数组的形式,另外一种则是链表的形式。AQS中的同步队列则是通过链式方式进行实现。
1.节点的数据结构,即AQS的静态内部类Node,节点的等待状态等信息;
2.同步队列是一个双向队列,AQS通过持有头尾指针管理同步队列;

3.独占锁
3.1 独占锁的获取(acquire方法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值