2013-01-08 124 views
3

我正在學習Java多線程,並且遇到問題,我無法理解Semaphores。我怎樣才能按此順序執行線程?例如:在image1上:第5個線程開始運行,然後1-st和2 -nd完成執行。使用信號量在Java中進行多線程編程

圖片2:

enter image description here


圖片1:

enter image description here

我現在上傳圖片以獲取更好的理解。 :))

+0

如果您希望某些任務在執行N個其他任務後執行,您可以使用['CountDownLatch'](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch。 HTML)。 – Pshemo

+0

在第一個圖上,線程並不是平行的,而是順序的。每個線程等待直到其他完成,然後創建一個新線程。第二個圖一次創建所有線程,但它們不同步。 –

+2

你永遠不應該試圖做到這一點。只需跳過並閱讀實踐中的併發。 – djechlin

回答

1

通常在Java中你使用互斥(也稱爲顯示器),禁止該該代碼區利用sychronized聲明

定義的兩個或多個線程訪問由互斥

proctected代碼區域

sychronized(mutex) { 
// mutual exclusive code begin 
// ... 
// ... 
// mutual exclusive code end 

} 

其中互斥定義爲如:

Object mutex = new Object(); 

爲了防止任務從beeing開始,你需要進階在java.util.concurrency包中定義的諸如障礙等先進技術。

但首先讓自己與​​聲明一起舒適。

如果你認爲你會經常使用的java多線程,則可能需要「在實踐中的Java併發」改爲

0

同步使用,這樣每個線程將進入該方法或該部分的代碼在一次。如果你想要

public class CountingSemaphore { 
    private int value = 0; 
    private int waitCount = 0; 
    private int notifyCount = 0; 

    public CountingSemaphore(int initial) { 
    if (initial > 0) { 
     value = initial; 
    } 
    } 

    public synchronized void waitForNotify() { 
    if (value <= waitCount) { 
     waitCount++; 
     try { 
     do { 
      wait(); 
     } while (notifyCount == 0); 
     } catch (InterruptedException e) { 
     notify(); 
     } finally { 
     waitCount--; 
     } 
     notifyCount--; 
    } 
    value--; 
    } 

    public synchronized void notifyToWakeup() { 
    value++; 
    if (waitCount > notifyCount) { 
     notifyCount++; 
     notify(); 
    } 
    } 
} 

這是一個計數信號量的實現。它保持計數器變量的'值','等待計數'和'notifyCount'。如果值小於waitCount且notifyCount爲空,則使線程等待。

您可以使用Java Counting Semaphore。從概念上講,信號量維護一套許可證。如果需要,每個獲取()都會阻止,直到獲得許可證爲止,然後將其獲取。每個版本()都添加一個許可證,可能會釋放一個阻止的收單機構。但是,沒有使用實際的許可證對象;信號量只是保持可用數量的計數,並據此採取行動。

信號量通常用於限制線程數量,而不是訪問某些(物理或邏輯)資源。例如,下面是使用信號來控制項目的泳池入口的類:

class Pool { 
    private static final MAX_AVAILABLE = 100; 
    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); 

    public Object getItem() throws InterruptedException { 
    available.acquire(); 
    return getNextAvailableItem(); 
    } 

    public void putItem(Object x) { 
    if (markAsUnused(x)) 
     available.release(); 
    } 

    // Not a particularly efficient data structure; just for demo 

    protected Object[] items = ... whatever kinds of items being managed 
    protected boolean[] used = new boolean[MAX_AVAILABLE]; 

    protected synchronized Object getNextAvailableItem() { 
    for (int i = 0; i < MAX_AVAILABLE; ++i) { 
     if (!used[i]) { 
      used[i] = true; 
      return items[i]; 
     } 
    } 
    return null; // not reached 
    } 

    protected synchronized boolean markAsUnused(Object item) { 
    for (int i = 0; i < MAX_AVAILABLE; ++i) { 
     if (item == items[i]) { 
      if (used[i]) { 
      used[i] = false; 
      return true; 
      } else 
      return false; 
     } 
    } 
    return false; 
    } 

} 

之前獲得項目的每個線程必須從信號量獲取許可,保證項目可供使用。當線程完成了該項目後,它將返回到池中,並且許可證返回到信號量,允許另一個線程獲取該項目。請注意,當調用acquire()時不會保持同步鎖定,因爲這會阻止將項目返回到池中。信號量封裝了限制對池的訪問所需的同步,與維護池本身一致性所需的任何同步分開進行。

一個信號量被初始化爲1,並且它被使用使得它最多隻有一個可用的許可證,可以用作互斥鎖。這通常被稱爲二進制信號量,因爲它只有兩種狀態:一種允許可用,或者零允許可用。當以這種方式使用時,二進制信號量具有屬性(與許多Lock實現不同),「鎖定」可以由所有者之外的線程釋放(因爲信號量沒有所有權概念)。這在一些特定的上下文中很有用,例如死鎖恢復。