2011-06-24 25 views

回答

11

一个可重入的锁定机制允许持有锁的线程重新进入关键部分。这意味着你可以做这样的事情:

public synchronized void functionOne() { 

    // do something 

    functionTwo(); 

    // do something else 

    // redundant, but permitted... 
    synchronized(this) { 
     // do more stuff 
    }  
} 

public synchronized void functionTwo() { 
    // do even more stuff! 
} 

在非重入锁,你将有一个死锁的情况,当你尝试调用functionTwo()functionOne()因为线程必须等待锁..它自己拥有。

死锁当然是线程1持有锁A并等待锁B而线程2持有锁B并等待锁A的恶劣情况。因此,两者都不能继续。此代码示例创建了一个僵局:

public synchronized void deadlock() throws InterruptedException { 
    Thread th = new Thread() { 
     public void run() { 
      deadlock(); 
     } 
    }.start(); 

    th.join(); 
} 

调用线程试图等待各地的产生的线程,这又不能打电话deadlock()直到呼叫方已退出。嘉潮!

+0

我猜OP意味着使用类java.util.concurrent.locks.ReentrantLock而不是'synchronized'块的例子。 –

+0

@Victor Sorokin我不确定他是否适合大写字母。不管是使用'synchronized'块还是'ReentrantLock'类,高级概念都是完全相同的。 – stevevls

0

即使通过输入其他代码块已经获得锁定,可重入锁定仍将允许锁定持有者输入代码块。一个不可重入的锁会让锁持有者自己锁定,因为它必须释放从另一个代码块获得的锁以重新获得同一个锁以进入需要代码块的嵌套锁。就死锁而言,如果您从受保护的代码块中调用受保护的代码块,您将需要一个可重入的锁(或者在等待自己时您会死锁)。

1

这里的僵局与ReentrantLock的

class Deadlock { 
    private static final ReentrantLock l1 = new ReentrantLock(); 

    public static void main(String[] args) { 
     Thread t = new Thread(new Runnable() { 
      public void run() { 
       System.out.println("A Trying to lock..."); 
       l1.lock(); 
       System.out.println("A Locked..."); 
       try { 
        Thread t = new Thread(new Runnable() { 
         public void run() { 
          System.out.println("B Trying to lock..."); 
          l1.lock(); 
          System.out.println("B Must not print"); 
          try { 
          } finally { 
           System.out.println("B Trying to unlock..."); 
           l1.unlock(); 
           System.out.println("B Unlocked..."); 
          } 
         } 
        }); 
        t.start(); 
        try { 
         t.join(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } finally { 
        System.out.println("A Trying to unlock..."); 
        l1.unlock(); 
        System.out.println("A Unlocked..."); 
       } 
      } 
     }); 
     t.start(); 
    } 
} 

一个例子来解决僵局,调用注释掉t.join,与封闭的try/catch一起。

6

死锁发生,然后线程等待一个永远不会发生的情况。

显而易见的情况是,当您试图锁定两个锁时,按不同的线程以不同的顺序锁定。

ReentrantLock lock1 = new ReentrantLock(); 
ReentrantLock lock2 = new ReentrantLock(); 

public void methodA() { 
    lock1.lock(); 
    lock2.lock(); 
    // do something and un lock both. 
} 

public void methodB() { 
    lock2.lock(); 
    lock1.lock(); 
    // do something and un lock both. 
} 

正如你可以看到它是可能的线程调用了methodA并获得锁1等待锁2,和另一个线程调用的methodB并获得锁2等待锁1。


但是,它可能导致线程自身死锁。一个示例是ReentrantReadWriteLock,因为它不支持将读锁升级到写锁。

ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 
rwl.readLock().lock(); 
// do we need to update? 
rwl.writeLock().lock(); // will wait for the readLock() to be released! 

一个不起眼的机会死锁自己是在暗示锁使用。所以锁用于即使静态初始化器块不​​

class A { 
    private static int VALUE; 
    static { 
     Thread t = new Thread() { 
      public void run() { 
       // waits for the A class to load. 
       VALUE = someLongTask(); 
      } 
     }; 
     t.start(); 
     // waits for the thread. 
     t.join(); 
    } 
} 

同样,你有一个僵局静态初始化器块隐含线程安全的!