2011-06-24 26 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(); 
    } 
} 

同樣,你有一個僵局靜態初始化器塊隱含線程安全的!