2011-04-23 55 views
0

美好的一天!無法同步Java中的線程(使用信號量)

我遇到了同步線程的問題。我正在寫程序,就像晚餐哲學家一樣。我有幾個進程(例如3個)和資源(例如4個)。每個進程只能使用2個免費資源。這意味着第一個進程只能使用第一個和第二個資源等。

我決定使用信號量來達到我的目的。問題是,仍然沒有同步。例如,如果第一個和第三個進程使用資源,則第二個進程必須等到他的資源不會被釋放。在我的程序中,有時會發生......有時它不會。

什麼問題?我該如何解決這個問題?

代碼是在這裏:

public class Sem 
{ 
    public Sem() 
    { 
     available = new ConcurrentHashMap< Integer, Semaphore >();//Resources. 

    for (int i = 1; i <= 4; i++) 
    { 
     available.put(i, new Semaphore(1, true));//Each resource contains semaphore. 
    } 
} 

public void start(final int id) 
{ 
    thisThread = new Thread() 
    { 
     public void run() 
     { 
      try 
      { 
       work(id);             //Try to take resourses. 
       Thread.currentThread().sleep(1000); 
       release(id);            //Release resources. 
      } catch (InterruptedException ex) { 
       Logger.getLogger(Sem.class.getName()).log(Level.SEVERE, null, ex); 
      } 

     } 
    }; 
    thisThread.start(); 
} 

public synchronized void work(int id) throws InterruptedException 
{ 
    available.get(id).acquire();           //Try to take resourse[id] and resourse[id+1] 
    available.get(id+1).acquire();           //Thread is blocking till it will be possible. 

    System.out.printf("Acquired [%s], id = %d\n",Thread.currentThread().getName(), id); 

} 

public void release(int id) 
{ 
    available.get(id).release();           //Release resources which hava been captured by thread. 
    available.get(id+1).release();           //After this other thread can take these resourses. 

    System.out.printf("Released [%s], id = %d\n",Thread.currentThread().getName(), id); 
} 


private ConcurrentHashMap< Integer, Semaphore > available;     //Integer - id of thread[1..4]; Semaphore - is gate with param (1) 
                      //Available - map of resources which can be busy by processes. 
Thread thisThread; 
} 

我啓動該程序是這樣的:

Sem sem = new Sem(); 

     sem.start(1); 
     sem.start(2); 
     sem.start(3); 

我有幾個輸出消息,但我最喜歡的:

Acquired [Thread-1], id = 1 
Acquired [Thread-3], id = 3 
Released [Thread-1], id = 1 
Acquired [Thread-2], id = 2 
Released [Thread-3], id = 3 
Released [Thread-2], id = 2 

過程2開始工作,而他不能這樣做!

回答

1

根據您的代碼和輸出,線程3可能釋放信號量3,以等待它的線程2 - 獲取它並在線程3完成之前打印消息。

我注意到你沒有同步發佈的方法。

我強烈建議在獲取和發佈時都使用同步塊。

synchronized(this) { 
    available.get(id).acquire();            
    available.get(id+1).acquire();           
} 

synchronized(this) { 
    available.get(id).release();            
    available.get(id+1).release(); 
} 
+0

如果我嘗試同步發佈它顯示'Acquired [Thread-1],id = 1; 獲取[Thread-3],id = 3',然後什麼都不做... – ExR 2011-04-23 17:10:32

+0

至少我認爲你是正確的線程... – ExR 2011-04-23 17:14:19

+0

如果不是同步(this),你嘗試同步(acquireObject)和同步(releaseObject)。線程2只是進入同步塊,並在信號量上阻塞 - 經典死鎖,因爲其他線程無法進入釋放。 – 2011-04-23 17:16:31

3

我認爲你應該以相反的順序釋放它們。

+0

您的意思是使用next: 'available.get(id + 1).release(); available.get(ID).release();'? – ExR 2011-04-23 14:25:14

+0

至少不起作用。我仍然收到如下信息: 'Acquired [Thread-1],id = 1; 獲取[Thread-3],id = 3; Released [Thread-1],id = 1; 獲取[Thread-2],id = 2; Released [Thread-3],id = 3; Released [Thread-2],id = 2;' – ExR 2011-04-23 14:48:39

0

您將首先完成資源,然後線程先釋放資源信號量。用以下替換釋放方法:

public void release(int id) { 
    resources.get(id + 1).release(); 
    resources.get(id).release(); 
    //resources.get(id + 1).release(); 
    System.out.printf("Released [%s], id = %d\n", Thread.currentThread().getName(), id); 
}