2016-05-30 53 views
3

我正在嘗試同步3個線程。它們中的每一個都處理沿着它自己的路徑移動的履帶。 不幸的是他們的路徑是這樣交叉的: image線程 - 使用標誌解鎖並嘗試/終於

爲了實現這個目標,我使用了鎖。共有兩個區塊:水平和垂直(我將它命名爲上面和下面)。問題是一個線程在同一時間想要在兩個共享部分。

我的問題是:

我可以解鎖使用標誌的try/finally從句裏面的鎖?

我的意思是,當一個線程解鎖try/finally子句中的一個鎖時,會設置一個標誌,並在finally子句中檢查該標誌是否設置,然後再次解鎖。我認爲這是一個安全的解決方案,但也許我錯了。

是否有任何其他方式來同步線程?

這是我的代碼:(它幾乎適用)

public void moveForward() throws InterruptedException { 
    redIsUpofAbove(); 
    int choose= 0; 
    if (Route.critcalSectionAbove.contains(head)) 
     choose= 1; 
    if (Route.critcalSectionBelow.contains(head)) 
     choose= 2; 

    switch (choose) { 
    case 1: { 
     boolean flag = true; 
     System.err.println(name + " Lock above"); 
     synchronization.aboveLock.lock(); 
     try { 

      takeNextGrid(); 
      Thread.sleep(sleepValue); 
      while (isInAboveCriticalSection()) { 
       takeNextGrid(); 
       Thread.sleep(sleepValue); 
       if (isInBelowCriticalSection()) {// Caterpillar is on two 
                // shared sections 
        System.out.println(name + " Lock below"); 
        if (!synchronization.belowLock.tryLock()) { 

         synchronization.aboveLock.unlock(); 
         System.out.println(name + " Unlock above"); 
         synchronization.belowLock.lock(); 
         flag = false; 
        } 
        try { 
         while (isInBelowCriticalSection()) { 
          takeNextGrid(); 
          if (!isInAboveCriticalSection() && flag) { 
           synchronization.aboveLock.unlock(); 
           flag = false; 
           System.out.println(name + " Unlock above"); 
          } 
          Thread.sleep(sleepValue); 
         } 
        } catch (Exception e) { 
        } finally { 
         synchronization.belowLock.unlock(); 
         System.err.println(name + "Unlock belovelock"); 
        } 
       } 
      } 
     } catch (Exception e) { 
     } finally { 
      if (flag) { 
       synchronization.aboveLock.unlock(); 
       System.out.println(name + " unlock above"); 
      } 
     } 

     break; 
    } 
    case 2: { 
     boolean flag = true; 
     System.err.println(name + " Lock below"); 
     synchronization.belowLock.lock(); 
     try { 

      takeNextGrid(); 
      Thread.sleep(sleepValue); 
      while (isInBelowCriticalSection()) { 
       takeNextGrid(); 
       Thread.sleep(sleepValue); 
       if (isInAboveCriticalSection()) { 
        if (!synchronization.aboveLock.tryLock() && flag) { 
         synchronization.belowLock.unlock(); 
         System.out.println(name + " Unlock below"); 
         synchronization.aboveLock.lock(); 
         flag = false; 
        } 
        try { 
         System.out.println(name + " Lock above"); 
         while (isInAboveCriticalSection()) { 
          takeNextGrid(); 
          if (!isInBelowCriticalSection() && flag == true) { 
           synchronization.belowLock.unlock(); 
           flag = false; 
           System.out.println(name + " Lock below"); 
          } 
          Thread.sleep(sleepValue); 
         } 
        } catch (Exception e) { 

        } finally { 
         synchronization.aboveLock.unlock(); 
         System.err.println(name + "Lock abovelock"); 
        } 

       } 
      } 
     } catch (Exception e) { 

     } finally { 
      if (flag) { 
       synchronization.belowLock.unlock(); 
       System.out.println("Opuszczam belowLock"); 
      } 
     } 

     break; 
    } 
    default: { 
     takeNextGrid(); 
     break; 
    } 
    } 

} 

最後一個問題:

有沒有一種方法來設置優先級醒來,在其上等待的線程一個鎖定的鎖?

回答

3

我可以使用標誌解鎖try/finally子句中的鎖嗎?

假設你沒有得到lock()呼叫,當你設置的標誌,那麼這應該正常工作之間的InterruptException;不過,我認爲在特定情況下這沒有任何意義。

如果您遇到異常情況,毛毛蟲會發生什麼情況?它消失了嗎?如果它仍然坐在路徑上的相同位置,即使在之後的處拋出異常,它仍然佔用該路徑的該部分;因此,釋放鎖定沒有意義。


是否有任何其他的方式來同步線程?

肯定有其他的同步機制,你可以嘗試(原子能,監控鎖等),但是這似乎是一個性能關鍵的應用程序沒有,所以我只想用什麼最有意義給你。如果鎖定有意義,則使用鎖定。現在

,如果你問,如果有不同的方式同步(即不同的策略,以便在您的路徑互斥),當時我有一個建議:

caterpillar tracks with 4 critical sections

您目前的解決方案有一個明顯的死鎖問題。由於belowabove部分是分開獲取的,藍色履帶(G2,「藍色」)可以獲取下部並移入,同時紅色履帶(G1,「紅色」)可以獲取上部並且進入。現在,任何一條履帶都無法完成自己的路線 - 它們陷入僵局(G1將無法前進到下部,G2將無法前進到上部)。

通過將路徑分割爲更多關鍵部分(如圖中所示),並在移動到關鍵部分時獲取多個部分,則可以避免這種死鎖情況。

只要確保「關鍵T」(即所有4個關鍵區域的聯合)中最多有2個毛毛蟲,那麼您始終可以避免死鎖。您可以通過創建帶有2個許可證的counting semaphore來完成此操作。您在獲取路徑中的第一個關鍵區域的鎖之前,以及在離開該區域之後的某個時間點。例如,對於紅,順序將是:

  1. acquire()在sempahore
  2. lock()以上,並通過它
  3. lock()下面左
  4. release()信號量
  5. 繼續前進前進進入中心,然後左下
  6. 一旦紅的尾巴離開中心,unlock()高於
  7. 一旦紅色的尾巴離開低於左,unlock()下面左
  8. 繼續通過非關鍵區域推進...

請注意,我們並不需要明確地鎖定中心,因爲它是隱含的保護信號量和其他鎖。

顯然還有其他方法可以用來確保「關鍵T」中只有2個毛毛蟲,但信號量似乎是最簡單的方法。

該解決方案避免死鎖如下:

  • 如果紅色是在上面,而藍色是在右下,然後藍色塊,直到它可以推進到中心之前,以上收購,使紅退出關鍵地區第一。
  • 如果藍色位於右下方,綠色位於左下方,則綠色會阻止,直到它可以在進入中心之前獲取右下方,從而允許藍色先退出關鍵區域。
  • 如果綠色位於左下方,且紅色位於上方,則紅色會阻止,直到它可以在前進到中心之前獲取左下方,從而允許綠色首先退出關鍵區域。

所有其他可能的配置也將避免死鎖 - 這些只是三個最有趣的情況。


有沒有一種方法來設置優先級醒來,在其上等待鎖定鎖的線程?

我不知道Java庫中的任何工具會實際上給你這樣的優先級保證。你要麼必須找到這樣做的第三方庫,或者實現你自己的。

一個簡單的方法來做到這一點只是爲不使用單獨的線程爲您的毛毛蟲。你可以用一個線程來完成所有的毛毛蟲邏輯 - 沒有理由說每個毛毛蟲都需要一個線程。如果你在一個線程中擁有所有的邏輯,那麼你處理毛毛蟲的順序會給你一個隱含的優先級排序。

+0

謝謝你的回答,這是非常有用的和有用的。 我想到了你的提示,並得出結論,它是正確的算法。我已經實施了它,並且......它的工作!這個練習的概念是使用單獨的線程並同步它們。我非常密切,但鎖上的信號燈變成我需要的東西。 再次感謝您。 – TomaszGrzybowski

0

道文算法運行良好。 這是紅毛蟲的代碼,其他毛毛蟲作品 原理相同,變化很小。我將路徑分爲三個關鍵部分:上方,左下方,右下方。中心區域有助於定義毛蟲何時離開關鍵部位,然後解鎖血塊。信號量保證最多兩個線程可以請求進入關鍵部分。在方法結束之前,標誌對於解鎖blocade非常有用,並且規定blocade只會被解除一次。

public final ReentrantLock aboveLock = new ReentrantLock(true); 
public final ReentrantLock LeftBelowLock = new ReentrantLock(true); 
public final ReentrantLock RightBelowLock = new ReentrantLock(true); 
public final Semaphore semaphore = new Semaphore(2); //counting semaphore 

private void movingRed() throws InterruptedException { 
    while (true) { 
     if (Route.critcalSectionAbove.contains(head)) { 
      synchronization.semaphore.acquireUninterruptibly(); 
      synchronization.aboveLock.lock(); 
      isAboveLock = true; 
      synchronization.LeftBelowLock.lock(); 
      isBelowLeftLock = true; 
      synchronization.semaphore.release(); 
      try { 
       while (!ifTailLeftCenter()) { // advance Critical-region 
               // until tail crosses center 
        takeNextGrid(); 
        Thread.sleep(sleepValue); 
       } 
       // caterpillar's tail left Center section 
       isAboveLock = false; 
       synchronization.aboveLock.unlock(); // unclocking above 
       while (isInBelowCriticalSectionLeft()) { // advance until 
                  // tail belong 
                  // to Left-Below 
        takeNextGrid(); 
        Thread.sleep(sleepValue); 
       } 
       // caterpillar's tail left LeftBelow section 
       isBelowLeftLock = false; 
       synchronization.LeftBelowLock.unlock(); 
      } catch (Exception e) { 
      } finally { 
       if (isAboveLock) 
        synchronization.aboveLock.unlock(); // in case exception 
                 // was throw before 
                 // unlock any lock 
       if (isBelowLeftLock) 
        synchronization.LeftBelowLock.unlock(); 
      } 
     } 
     // caterpillar moving through non-critical region 
     takeNextGrid(); 
     Thread.sleep(sleepValue); 
    } 
} 

感謝您的幫助。