2011-04-23 57 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); 
}