Java ReentrantLock详解:多线程打印奇偶数并发控制

0 下载量 94 浏览量 更新于2024-09-02 收藏 194KB PDF 举报
Java中的ReentrantLock是一种高级互斥锁,相较于传统的`synchronized`关键字,它提供了更丰富的锁定和解锁机制,允许更精细的控制线程间的同步行为。本文将深入探讨ReentrantLock在Java中的使用以及其工作原理。 首先,我们回顾一下传统`synchronized`的使用场景。在上述例子中,两个线程(打印奇数和打印偶数)需要竞争对共享数据`MyNumber`的访问权限。使用`synchronized`时,如果一个线程获得了锁,其他尝试获取该锁的线程将会阻塞,直到锁被释放。然而,这种机制可能导致线程间的死锁问题,尤其是在复杂的多线程环境中。 ReentrantLock的引入正是为了解决这些问题。它提供了一种可重入锁,即一个已经持有锁的线程可以再次获得同一把锁,这是`synchronized`做不到的。这使得线程在完成特定操作后可以主动释放锁,再重新获取,避免了死锁可能。 在ReentrantLock的使用上,首先需要创建一个`ReentrantLock`实例,然后使用`lock()`方法获取锁,用完后调用`unlock()`释放锁。例如,我们可以创建一个`ReentrantLock`对象替换`synchronized`: ```java private final ReentrantLock lock = new ReentrantLock(); // 在打印奇数或偶数的方法中 lock.lock(); // 获取锁 try { if (n.isOdd()) { System.out.println("old: " + n.getVal()); n.increase(); } else { lock.unlock(); // 如果不是奇数,先解锁 n.waitToOdd(); // 等待变为奇数 } } finally { lock.unlock(); // 无论是否打印,都确保最终释放锁 } ``` `waitToOdd()`和`waitToEven()`方法则是调用`lock.lock()`来获取锁,然后调用`unlock()`释放锁并进入等待状态,直到`notify()`被调用唤醒。这样,当数据变为奇数时,打印奇数的线程会被唤醒,然后继续执行,而不会阻塞等待偶数的线程。 ReentrantLock还提供了其他特性,如条件变量(Condition),允许线程在满足特定条件时进入等待队列,而不必一直持有锁。这对于复杂的同步场景非常有用,可以减少锁的持有时间,提高并发性能。 总结来说,ReentrantLock为Java程序员提供了一种更灵活、更安全的同步机制,它允许更细致的控制线程交互,并能有效避免`synchronized`可能导致的问题,比如死锁。通过合理的使用,ReentrantLock可以显著提升多线程程序的效率和可维护性。