2011-12-18 70 views
2

有n个线程可以访问的单例类。
每个线程加载此类的实例并在一个循环中从此类调用一个方法。执行线程“one by one”

我必须控制执行的流程,以便每个线程都可以调用方法一和暂停,只有在所有线程调用该方法后才能恢复工作。线程可以按任意顺序调用方法,只需要在移动循环之前执行一次方法。

这是我尝试做:

在螺纹:

while (some condition){ 
    ObjectType obj = theSingleton.getInstance().getSharedObject(); 
    obj.SomeMethod(threadID); 
    if (obj.waitisneeded()) 
    synchronized (obj) { 
     obj.wait(); 
    } 
} 

我在的someMethod做:

public synchronized void SomeMethod(String threadID) { 
hashMap.put(threadID,true); 
some job here 
} 

和waitisneeded:

public synchronized boolean waitisneeded(){ 
{ 

    Iterator iter = hashMap.entrySet().iterator(); 

    boolean alldone = false; 

    while (iter.hasNext()) { 
     Map.Entry me = (Map.Entry) iter.next(); 
     String key = me.getKey().toString(); 
     alldone = (Boolean)me.getValue(); 

     if(!alldone) { 
    return false; 
     } 
    } 

    //set all values to false 
iter = hashMap.entrySet().iterator(); 
while (iter.hasNext()) { 
    Map.Entry me = (Map.Entry) iter.next(); 
    String key = me.getKey().toString(); 
    me.setValue(false);  
}  
this.notifyAll(); 
return true;    

运行这让我感到意外编辑结果和死锁。

我该如何解决?

注意:我无法改变线程的创建方式,我只能改变这些方法! (加在线程那里等待是while循环)

+0

待办事项你知道每个调用'obj.SomeMethod()'之前创建了多少个线程? – 2011-12-18 22:21:31

+0

你怎么知道什么时候“所有期望的线程现在称为单例”的时间点已经达到? – 2011-12-18 22:30:25

+0

@TheScrumMeister Scrum Meister是的,我知道线程数 – kenny 2011-12-19 05:11:52

回答

2

如果你知道线程数,你可以使用一个CyclicBarrier

static final CyclicBarrier barrier = new CyclicBarrier(numberOfThreads); 

然后,在点要在其中进行的所有主题等待别人,你叫:

​​

如果有还未到达该行一个线程,该线程调用await()将阻塞。一旦所有线程都到达并致电await(),它们将全部恢复。

每次你必须建立一些同步机制时,一定要检查包java.util.concurrent。那里有许多精彩的课程,由专家创建。大多数情况下,你不需要自定义的东西,如果你这样做,在同一个包中有一些类将使得它几乎不需要直接使用等待/通知 - 并且相信我,你想避免使用这些方法直接;正如你所看到的,你很容易陷入僵局!

+0

我认为CyclicBarrier有问题,因为var是静态的。在我的应用程序中,这种情况可能会并行发生多次! X线程(我忘了提及),getSharedObject被生成并存储在单例的hashmap变量中。所以每一组线程都可以访问自己的对象。这就是为什么我试图使用锁,并将它作为LOCK的自我getSharedObject!如果我使用静态我将不得不为每个getSharedObject – kenny 2011-12-19 05:07:42

+0

创建新的变量那么,我不知道你的应用程序如何工作。我相信你可以适应你的情况!整个想法是,在恢复之前必须等待彼此的线程必须共享一个CyclicBarrier。一定要正确发布障碍! (也就是说,由于您将有许多CyclicBarriers,因此最好使用并发集合来保存实例,例如ConcurrentHashMap)。 – 2011-12-19 12:12:40

0

这是一种典型的多线程情况,称为Rendez-Vous(法语单词意思是“约会”)。基本上你的N线程将有一个约会,应该都在等待一个点,直到所有人达到它。正如@布鲁诺所说的,您可以使用CyclicBarrier对象来管理这种情况。如果你的场景只运行一次,那么你也可以使用CountDownLatch

这里是你如何能做到这一点:

static final CountDownLatch rendezVousPoint = new CountDownLacth(numberOfThreads); 

//Every thread does the following right before waiting on the rendez vous point 
rendezVousPoint.countDown(); 
rendezVousPoint.await(); 

在这种情况下,每个线程将在await()方法阻止,直到最后一个线程到达并释放所有的人(rendezVousPoint数为0)

+0

我不确定我喜欢这个(ab)使用'CountDownLatch'。你正在颠覆一个'CountDownLatch',使其行为完全像一个'CyclicBarrier'(它已经被构建来处理这种情况)。像你这样调用的方法'CDL.countDown()'和'CDL.await()',其行为大体上类似于'CB.await()',但是它们有2种方法用于某种目的(这不是被称为一个权利之后):通常,工作线程会调用CDL.countDown(),只有一个主线程会调用CDL.await(),才能阻塞,直到所有工作线程完成任务。 – 2011-12-18 23:56:58

+0

@BrunoReis感谢您的评论,我倾向于对此表示不同意。按照官方的java文档,一个接一个地执行'CDL.countDown()'和'CDL.await()'没有任何问题。一个'CyclicBarrier'(根据文档)是一个'CountDownLatch'的可重用(可以设置和重置几次)版本, – GETah 2011-12-19 14:56:39