ReentrantLock.lock()不会阻止其他线程

时间:2014-03-02 20:43:37

标签: java multithreading concurrency reentrantlock

我很难理解ReentrantLock.lock()

的行为

我有以下课程

import java.util.concurrent.locks.*;

class BlockingClass {

    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    public void a() {
        lock.lock();
        System.out.println("called in method a(): lock()");

        try {
            System.out.println("called in method a(): await()");
            condition.await();
        } 
        catch (InterruptedException e) {} 
        finally {
            lock.unlock();
            System.out.println("called in method a(): unlock() ");
        }
    }

    public void b() {
        lock.lock();
        System.out.println("called in method b(): lock()");

        System.out.println("called in method b(): signalAll()");
        condition.signalAll();

        lock.unlock();
        System.out.println("called in method b(): unlock() ");
    }
}

我使用以下测试运行:

class BlockingClassTest {
    public static void main(String[] args) throws InterruptedException {

        final BlockingClass blockingClass = new BlockingClass();

        new Thread() {
            public void run() {
                System.out.println("Thread1 calling a()");
                blockingClass.a();
            }
        }.start();

        Thread.sleep(1000); 

        new Thread() {
            public void run() {
                System.out.println("Thread2 calling b()");
                blockingClass.b();
            }
        }.start();
    }
}

我原本预计会陷入僵局。一旦a()方法调用lock.lock(),我希望任何调用b()方法的人都必须等待b的lock.lock(),直到调用a()的线程调用lock.unlock()。但是因为a()正在等待b()调用condition.signalAll(),所以这两种方法都应该永远被阻止。

相反,这是我在控制台中得到的输出:

Thread1 calling a()
called in method a(): lock()
called in method a(): await()
Thread2 calling b()
called in method b(): lock()
called in method b(): signalAll()
called in method a(): unlock() 
called in method b(): unlock() 

我对lock()和unlock()的正确使用和功能有什么误解?

3 个答案:

答案 0 :(得分:5)

你没有误解ReentrantLock,你误解了ConditionCondition绑定到一个锁,Condition.await()将有效解锁,检查并等待,然后重新锁定锁。请参阅Condition.await()

a()lock()await()之间以及await()unlock()的回复之间,您的锁定正如您所期望的那样。在await()的来电中,Condition正在管理它。

这是“条件变量”的一般概念的一部分;这就是为什么你找到的任何线程库将某种锁与一个条件相关联(例如在POSIX C中,pthread_cond_wait需要一个条件变量一个互斥锁。)

查看关于condition variables的维基百科文章,它详细解释了这种行为及其原因。

答案 1 :(得分:2)

您对condition.await();的调用将释放锁定,使线程处于wait状态,因此线程b可以获得锁定。

a()方法会在b()释放锁定后继续运行,因为您已发出信号。

答案 2 :(得分:1)

答案已经给出,但我认为我只引用javadocs for Condition.await()来提供更多背景信息:

  

使当前线程等到信号通知或中断为止。

     

与此条件关联的锁是原子释放,并且当前线程因线程调度而被禁用,并且在发生以下四种情况之一之前处于休眠状态:

     
      
  1. 其他一些线程调用此Condition的signal方法,当前线程恰好被选为要被唤醒的线程;或
  2.   
  3. 其他一些线程为此Condition调用signalAll方法;或
  4.   
  5. 其他一些线程中断当前线程,并支持线程挂起中断;或
  6.   
  7. 发生“虚假唤醒”。
  8.         

    在所有情况下,在此方法返回之前,当前线程必须重新获取与此条件关联的锁。当线程返回时,保证保持此锁定。

因此,当您调用condition.await()时,它会释放锁定,允许其他线程进入锁定部分。这与Object.wait()代码块内的synchronized行为相同。