关于多线程同步的初步教程--可重入锁的设计及使用
上一篇中的Mutex是一个独占锁,只能有一个线程拥有该锁,并且即时是同一个线程,如果已经持有一个Mutex时,再次企图获取该锁时仍然会阻塞。有的时候我们需要锁能够像Java语言的synchronized那样,同一个线程可以重新进入,只要已经拥有了该锁,而不用在该锁上阻塞。我们可以对上篇中的Mutex的实现进行改造,实现一个可重入的锁--ReentrantLock。这需要ReentrantLock中记录当前锁的拥有者(线程),同时设置一个整型变量,记录当前线程进入的次数。
- public class ReentrantLock implements Sync {
-
- protected Thread owner_ = null;
- protected long holds_ = 0;
-
- //......
-
- }
在获取、释放锁时,首先判断该线程是否是锁的拥有者。如果是当前线程已经拥有该锁,则在每一次acquire()时增1,在release()时减1在次数减少到0时,说明该锁的当前拥有者已经完全释放该锁,不再拥有该锁。所以,将拥有者设置为null。如果当前线程不是锁的拥有者,那么在企图获取锁时在该锁上wait(),在release()方法中,如果拥有者已经完全释放锁,那么就将拥有者清零,并notify()其它线程。
- public void acquire() throws InterruptedException {
- if (Thread.interrupted()) throw new InterruptedException();
- Thread caller = Thread.currentThread();
- synchronized(this) { // 在this上同步
- if (caller == owner_)
- ++holds_;
- else {
- try {
- while (owner_ != null) wait();
- owner_ = caller;
- holds_ = 1;
- }
- catch (InterruptedException ex) {
- notify();
- throw ex;
- }
- }
- }
- }
-
- public synchronized void release() { //在this上同步
- if (Thread.currentThread() != owner_)
- throw new Error("Illegal Lock usage");
-
- if (--holds_ == 0) {
- owner_ = null;
- notify();
- }
- }
注意上面的代码要对owner_和holds_在this上进行同步,以解决在这两个变量上的竞态条件。attempt()方法实现和Mutex类似,也添加了锁拥有者的检查及计数:
- public boolean attempt(long msecs) throws InterruptedException {
- if (Thread.interrupted()) throw new InterruptedException();
- Thread caller = Thread.currentThread();
- synchronized(this) {
- if (caller == owner_) {
- ++holds_;
- return true;
- }
- else if (owner_ == null) {
- owner_ = caller;
- holds_ = 1;
- return true;
- }
- else if (msecs <=&nb
补充:软件开发 , Java ,