我们在使用synchronized进行同步的是否,如果一个线程获得了一个对象的锁,而这个线程需要在执行的过程中挂起,那么我们就可以调用这个对象的wait方法,释放锁的资源,挂起,等待被唤醒重新获得锁的资源,而我们如果用可重入锁来进行同步,想选择挂起应该怎么做呢,Lock中引入了Condition这个类来做这件事,接下来我们就看一下它是怎么实现的:
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.take();
queue.add("add");
LinkedBlockingQueue就是利用Condition来做线程阻塞的,所以,上面的take 方法就是我们的入口:
public E take() throws InterruptedException {
E x;
int c = -1;
//获得当前元素的个数
final AtomicInteger count = this.count;
//获得take锁
final ReentrantLock takeLock = this.takeLock;
//获得锁资源
takeLock.lockInterruptibly();
try {
//如果当前可以获取的元素的数目是0.那么就要进入阻塞状态,并且释放锁的资源
while (count.get() == 0) {
notEmpty.await();
}
//到这里说明成功获取到了元素
x = dequeue();
c = count.getAndDecrement();
//如果还有可以获取的资源,那么唤醒下一个需要获取资源的线程
if (c > 1)
notEmpty.signal();
} finally {
//解锁
takeLock.unlock();
}
//说明在当前线程获取资源的时候队列是满的,就是可能会有阻塞的放元素的线程,所以这个时候尝试唤醒那个线程
if (c == capacity)
signalNotFull();
return x;
}
这个方法还是挺清晰的,首先会获得take锁,判断这个时候是否有可以获取的数据,没有给的活就会调用condition的await 方法释放锁的资源,进入挂起状态:
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
采用可中断的方式获取锁的资源:
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())