2015-04-09 3 views
0

Я ищу, чтобы узнать об использовании Java CountDownLatch для управления исполнением потока.Java CountDownLatch с потоками

У меня есть два класса. Один из них называется Poller, а другой - Referendum. Потоки создаются в классе Referendum, а их методы run() содержатся в классе Poller.

В классах Poller и Referendum я импортировал заставку обратного отсчета java через импорт java.util.concurrent.CountDownLatch.

Я в основном хотят понять, почему и где эти *.countDown(); и *.await(); заявления должны быть применены, а также понять, если я правильно инициализирован в countDownLatch в Poller конструктора.

Полный код для двух классов:

import java.util.concurrent.CountDownLatch; 

public class Poller extends Thread 
{ 
private String id;     // pollster id 
private int pollSize;    // number of samples 
private int numberOfPolls;   // number of times to perform a poll 
private Referendum referendum;  // the referendum (implies voting population) 
private int sampledVotes[];   // the counts of votes for or against 
static CountDownLatch pollsAreComplete; //the CountDownLatch 


/** 
* Constructor for polling organisation. 
* @param r A referendum on which the poller is gathering stats 
* @param id The name of this polling organisation 
* @param pollSize The size of the poll this poller will use 
* @param pollTimes The number of times this poller will conduct a poll 
* @param aLatch The coutn down latch that prevents the referendum results from being published 
*/ 

public Poller(Referendum r, String id, int pollSize, int pollTimes, CountDownLatch aLatch) 
{ 
    this.referendum = r; 
    this.id = id; 
    this.pollSize = pollSize; 
    this.numberOfPolls = pollTimes; 
    this.pollsAreComplete = aLatch; 
    aLatch = new CountDownLatch(3); 

    // for and against votes to be counted 
    sampledVotes = new int[2]; 
} 


// getter for numberOfPolls 
public int getNumberOfPolls() 
{ 
    return numberOfPolls; 
} 

@Override 
//to use the countdown latch 
public void run() 
{  
    for (int i = 0; i < getNumberOfPolls(); i++) 
    { 
     resetVotes(); 
     pollVotes(); 
     publishPollResults(); 
    } 
} 

// make sure all sampledVotes are reset to zero 
protected void resetVotes() 
{ 
    // initialise the vote counts in the poll 
    for (int i = 0; i < sampledVotes.length; i++) 
    { 
     sampledVotes[i] = 0; 
    } 
} 

// sampling the way citizens will vote in a referendum 
protected void pollVotes() 
{ 
    for (int n = 0; n < pollSize; n++) 
    { 
     Citizen c = referendum.pickRandomCitizen(); 

     //As things stand, pickRandomCitizen can return null 
     //because we haven't protected access to the collection 
     if (c != null) 
     { 
      sampledVotes[c.voteFor()]++; 
     } 
    } 
} 

protected void publishPollResults() 
{ 
    int vfor = 100 * sampledVotes[Referendum.FOR]/pollSize; 

    int vagainst = 100 * sampledVotes[Referendum.AGAINST]/pollSize; 

    System.out.printf("According to %-20s \t(", this.id + ":"); 

    System.out.print("FOR " + vfor); 

    try 
    { 
     Thread.sleep(1000); 
    } catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 

    System.out.println(", AGAINST " + vagainst + ")"); 
} 
} 

И

import java.util.LinkedList; 
import java.util.List; 
import java.util.concurrent.CountDownLatch; 


public class Referendum 
{ 
private List<Citizen> citizens;   //voters 
private List<Poller> pollers;   //vote samplers 
public static final int FOR = 0;  //index for votes array 
public static final int AGAINST = 1; //index for votes array 
private int votes[];     //for and against votes counters 


public Referendum(int population) 
{ 
    citizens = new LinkedList<Citizen>(); 
    pollers = new LinkedList<Poller>(); 

    // initialise the referendum with the population 
    for (int i = 0; i < population; i++) 
    { 
     Citizen c = new Citizen(i % 4); //suppose equal party membership 
     citizens.add(c); 
    } 

    votes = new int[2]; //in this example, only For or Against 
} 

public void addPoller(Poller np) 
{ 
    pollers.add(np); 
} 

public Citizen removeCitizen(int i) 
{ 
    return citizens.remove(i); 
} 

public List<Poller> getPollers() 
{ 
    return pollers; 
} 

public void startPollsWithLatch() 
{ 
    //create some poller threads that use a latch 
    addPoller(new Poller(this, "The Daily Day", 100, 3, Poller.pollsAreComplete)); 
    addPoller(new Poller(this, "Stats people", 100, 3, Poller.pollsAreComplete)); 
    addPoller(new Poller(this, "TV Pundits", 100, 3, Poller.pollsAreComplete)); 

    // start the polls 
    for (Poller p : pollers) 
    { 
     p.start(); 

    } 
} 



// pick a citizen randomly - access not controlled yet 
public Citizen pickRandomCitizen() 
{ 
    //TODO add code to this method for part (b) 

    Citizen randomCitizen; 
    // first get a random index 
    int index = (int) (Math.random() * getPopulationSize()); 
    randomCitizen = citizens.remove(index); 

    return randomCitizen; 
} 

// Counting the actual votes cast in the referendum 
public void castVotes() 
{ 
    for (int h = 0; h < getPopulationSize(); h++) 
    { 
     Citizen c = citizens.get(h); 

     votes[c.voteFor()]++; 
    } 
} 

// tell the size of population 
public int getPopulationSize() 
{ 
    return citizens.size(); 
} 

// display the referendum results 
public void revealResults() 
{ 
    System.out.println(" **** The Referendum Results are out! ****"); 

    System.out.println("FOR"); 
    System.out.printf("\t %.2f %%\n", 100.0 * votes[FOR]/getPopulationSize()); 

    System.out.println("AGAINST"); 
    System.out.printf("\t %.2f %%\n", 100.0 * votes[AGAINST]/getPopulationSize()); 
} 

public static void main(String[] args) 
{ 
    // Initialise referendum. The number of people 
    // has been made smaller here to reduce the simulation time. 
    Referendum r = new Referendum(50000); 


    r.startPollsWithLatch(); 

    r.castVotes(); 

    // reveal the results of referendum 
    r.revealResults(); 
} 
} 

В двух словах ... Все потоки должны выполнить publishPollResults(); заявление ПЕРЕД revealResults(); выполняется.

+0

но каково ожидаемое поведение? Что вы хотите синхронизировать и почему. Как это происходит, начнется 3-го Poller, а затем каждый будет голосовать 3 раза и распечатает свои повторные результаты. – Zielu

+0

вы создаете countdownlatch локально в потоке poller. Как другие потоки будут обращаться к нему. Может быть, вам нужно создать обратную защелку в главном и передать ее другим потокам, к которым вы должны присоединиться. В конце запуска, в главном вызове ожидание. Хороший пример имеет javadoc countdownlatch. – bl3e

+0

@Zielu Все потоки должны выполнять publishPollResults(); утверждение перед раскрытием результатов(); выполняется. –

ответ

0

OK,

Теперь, если publishPollResults должно быть сделано все до reavelResults, то просто нужно ждать для правильного подсчета в вашем reaveal методе. Но для этого защелка также должна быть передана объекту референдума не только с помощью Pollers.

так, пусть референдум создает защелку и передать его в пуллеры:

public class Referendum 
{ 
    CountDownLatch pollsAreComplete; 
    ... 

    public void startPollsWithLatch() 
    { 
     pollsAreComplete = new CountDownLatch(3); //create new latch to know when the voting is done 
     //create some poller threads that use a latch 
     addPoller(new Poller(this, "The Daily Day", 100, 3, pollsAreComplete)); //pass it to pollers 
     addPoller(new Poller(this, "Stats people", 100, 3, pollsAreComplete)); 
     addPoller(new Poller(this, "TV Pundits", 100, 3, pollsAreComplete)); 

     // start the polls 
     for (Poller p : pollers) 
     { 
      p.start(); 
     } 
    } 

    public void revealResults() 
    { 

    pollsAreComplete.await(); //we can pass this line only if the latch count went to 0 

    System.out.println(" **** The Referendum Results are out! ****"); 
    .... 
    } 

} 

так Пуллеры следует разделить на защелку. Вы используете статическую переменную, которая является OKish, но вы хотите иметь возможность использовать Pollers с различными референдумами. Итак, лучше, если у вас есть поле экземпляра и передайте его в конструкторе (вы начинаете с конструктора, но затем передаете значение статической переменной, которая не имеет смысла (и она actaully всегда была нулевой).

public class Poller extends Thread 
{ 
    ... 
    private CountDownLatch pollsAreComplete; //the CountDownLatch shared with referendum 

    public Poller(Referendum r, String id, int pollSize, int pollTimes, CountDownLatch aLatch) 
    { 
     ... 
     this.pollsAreComplete = aLatch; 
    } 

    public void run() 
    {  
     for (int i = 0; i < getNumberOfPolls(); i++) 
     { 
      resetVotes(); 
      pollVotes(); 
      publishPollResults(); 
     } 
     pollsAreComplete.countDown(); //voting is finished, let the referendum publish the results. 
    } 

} 

так как только Poller закончил свою работу он опускает защелку, и когда все это делать референдум может продолжаться и распечатать результаты.

Разум вы все Poller нить будет публиковать свои результаты в 3 раза (так как они имеют для петля), и только когда все 3 являются циклами вниз, они будут сигнализировать о референдуме.

Если вы хотели бы, чтобы 3 отдельных этапа референдума было бы очень трудно достичь, если с защелкой, поскольку он не может быть сброшен, когда он не сбрасывается, когда он был сброшен до 0.

0

Если я правильно понял, вы хотите, чтобы все потоки выполнялись до того, как результаты будут показаны , Для этого требуется один экземпляр CountDownLatch в классе Referendum, который передается конструктору каждого потока Poller.Каждый Poller называет countdown() на защелках, когда он заканчивает опрос, и Referendum звонков await() спать, пока защелку отсчет не достигнет нуль:

class Referendum { 
    private CountDownLatch latch; 
    public CountDownLatch getLatch() { 
    return latch; 
    } 

    // ... 

    public void startVotesWithLatch() { 
    // You don't need to pass the latch in constructor, 
    // as you can retrieve it from the referendum object passed 
    addPoller(new Poller(this, "Stats people", 100, 3)); 
    // Add other pollers 
    // Start all pollers 
    for (Poller p : pollers) { 
     p.start(); 
    } 
    // Wait for all pollers to finish 
    latch.await(); 
    } 
} 

И в Poller классе удалить защелки переменного, поскольку она не нужна, то в publishPollResults() метод:

public void publishPollResults() { 
    // Everything stays the same here, except we decrease the latch 
    // when finished... 
    referendum.getLatch().countDown(); 
} 

однако обратите внимание, что этот тип синхронизации довольно прост и не обязательно требует CountDownLatch, вы можете просто нерест свои Poller темы, а затем вызвать join() в основной теме (это остановит основной поток, пока дочерние потоки не закончат выполнение).

Смежные вопросы