以下代码取自JavaDoc of 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();
}
}
}
想象一下2个线程, Consumer 和 Producer ,一个使用take
,一个put
在BoundedBuffer
的单个实例上。
让我们说消费者先行,运行take()
,然后锁定lock
,现在循环notEmpty.await();
。
现在 Producer 如何能够进入put()
方法,锁定{em>消费者已经拥有的lock
?
我在这里缺少什么?当线程正在等待其中一个条件时,lock
“暂时释放”吗?锁的重入究竟是什么意思?
答案 0 :(得分:28)
Lock
和synchronized
允许线程在等待时放弃锁定,而另一个线程可以获得锁定。要停止等待,线程必须重新获取锁定。
注意:它们不会完全释放它,如果你采用堆栈跟踪,你可以有多个线程,它们似乎一次持有锁,但最多其中一个将运行(其余的将阻塞)
与此条件关联的锁被原子释放,当前线程因线程调度而被禁用,并且在发生以下四种情况之一之前处于休眠状态:
- 其他一些线程调用此Condition的signal()方法,当前线程恰好被选为要被唤醒的线程;或
- 其他一些线程为此Condition调用signalAll()方法;或
- 其他一些线程中断当前线程,并支持线程挂起中断;或
- 发生“虚假唤醒”。
在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时,保证保持此锁
答案 1 :(得分:6)
就重新入侵而言,这意味着拥有某个锁的线程可以再次重新获得相同的锁。如果不是这样,synchronized
方法将无法调用同一对象的另一个synchronized
方法。
重新入侵不参与了解你的问题。
答案 2 :(得分:-1)
我用单显示器测试下面的代码,下面总是表现更好 - 在2核心机器上测试,条件性能平均低于10-15%
final Object sync = new Object();
AtomicInteger add=new AtomicInteger();
AtomicInteger remove=new AtomicInteger();
final Object[] items = new Object[1];
int putptr, takeptr, count;
public void add(Object x) throws InterruptedException {
add.incrementAndGet();
synchronized (sync) {
while (count == items.length)
sync.wait();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
sync.notify();
}
}
public Object remove() throws InterruptedException {
remove.incrementAndGet();
synchronized (sync) {
while (count == 0)
sync.wait();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
sync.notify();
return x;
}
}
public static void main(String[] args) {
final BoundedBuffer bf=new BoundedBuffer();
Thread put =new Thread(){
public void run(){
try {
while(true)
bf.add(new Object());
} catch (InterruptedException e) {
}
}
};
put.start();
Thread take= new Thread(){
public void run(){
try {
while(true)
bf.remove();
} catch (InterruptedException e) {
}
}
};
take.start();
try {
Thread.sleep(1000L);
put.interrupt();
take.interrupt();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("add:"+bf.add);
System.out.println("remove:"+bf.remove);