2016-07-03 2 views
2

J'écris cette classe qui simule un point de barrière. Lorsqu'un thread atteint ce point de blocage, il ne peut pas continuer tant que les autres threads n'ont pas atteint ce point. J'utilise un compteur pour suivre le nombre de threads qui sont arrivés à ce point. Supposons que la classe attend N + 1 threads, mais seulement N threads. Dans ce cas le programme gardera tous les threads en attente car il pense qu'il y a encore un thread à arriver.Libérer tous les threads en attente

Je veux écrire une méthode qui me permettra de libérer tous les threads en attente, que le programme pense ou non qu'il y a encore plus de threads pour arriver au point de barrière.

Mon programme d'attendre toutes les discussions,

public volatile int count; 
public static boolean cycle = false; 

public static Lock lock = new ReentrantLock(); 
public static Condition cv = lock.newCondition(); 

public void barrier() throws InterruptedException { 
    boolean cycle; 
    System.out.println("lock"); 
    lock.lock(); 
    try { 
     cycle = this.cycle; 
     if (--this.count == 0) { 
      System.out.println("releasing all threads"); 
      this.cycle = !this.cycle; 
      cv.signalAll(); 
     } else { 
      while (cycle == this.cycle) { 
       System.out.println("waiting at barrier"); 
       cv.await(); // Line 20 
      } 
     } 
    } finally { 
     System.out.println("unlock"); 
     lock.unlock(); 
    } 
} 

Je pensais que je pouvais simplement créer une méthode qui appelle la méthode signalAll() et tous les fils seraient libres. Cependant, un problème que j'ai est que si le programme attend plus de threads, il maintiendra un verrou car il attendra à la ligne 20.

Y at-il un moyen de contourner ce verrou? Comment dois-je aborder ce problème?

+0

'this.cycle = this.cycle; cv.signalAll(); '? – immibis

+0

S'il s'agit d'une barrière réutilisable, vous devez également décider ce qui doit arriver avec les threads qui arrivent après votre appel freeAll, et freeAll doit réinitialiser ce.count. – immibis

Répondre

0

meilleure idée - utiliser la norme java.util.concurrent primitive - CyclicBarrier avec la méthode 'reset':

/** 
* Resets the barrier to its initial state. If any parties are 
* currently waiting at the barrier, they will return with a 
* {@link BrokenBarrierException}. Note that resets <em>after</em> 
* a breakage has occurred for other reasons can be complicated to 
* carry out; threads need to re-synchronize in some other way, 
* and choose one to perform the reset. It may be preferable to 
* instead create a new barrier for subsequent use. 
*/ 
public void reset()