4

我很难理解 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() 的正确使用和功能有什么误解?

4

3 回答 3

6

你不是误会ReentrantLock,你是误会Condition。ACondition与锁绑定,Condition.await()将有效地解锁、检查和等待,然后重新锁定锁。见Condition.await()

a()、 之间lock()和 调用await()以及 返回 和 之间await()unlock()您的锁的行为与您预期的一样。在对 的调用中await()Condition正在管理它。

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

查看有关条件变量的 Wikipedia 文章,它详细解释了这种行为及其原因。

于 2014-03-02T20:51:52.307 回答
2

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

一旦释放了锁定,您的a()方法将继续运行,因为您发出了条件信号。b()

于 2014-03-02T20:51:59.230 回答
1

答案已经给出,但我想我只是引用javadocsCondition.await()以提供更多上下文:

使当前线程等待,直到它发出信号或中断。

与此 Condition 关联的锁被自动释放,并且当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:

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

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

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

于 2014-03-02T21:06:11.523 回答