Gå til innhold

Synkronisering av PriorityQueue med flere tråder


Anbefalte innlegg

Etter å ha fått til PriorityQueue er jeg nå igang med en ny oppgave.

 

Brukeren skal skrive inn en setning som skal legges inn i en PriorityQueue. Deretter skal 3 tråder konkurere om å hente ut det brukeren hadde skrevet inn.

 

Et krav er at dette blir gjort synkronisert, slik at kun en tråd kan lese fra (og skrive til) ved ethvert tidspunkt. Dette kan gjøres ved at trådene deler et objekt "Guard" som har synkronisert tilgang.

 

Det at oppgaven bruker ordet "kan" betyr at vi kan velge alternative måter å gjøre dette på. Det står i midlertid i klartekst at PriorityQueue skal brukes, så jeg tror ikke det er greit å bruke hverken "PriorityBlockingQueue" eller SynchronizedPriorityQueue. Jeg ser for meg at jeg må gjøre følgende:

  1. Lage en synkronisert klasse "Guard" som vidresender PriorityQueue'en som den får fra de tre trådene, til utskriftsklassen
  2. Lage et objekt av denne klassen
  3. Starte de tre trådene, som sender parameter for PriorityQueue'en til Guard-objektet.

Høres det ut som jeg tenker riktig?

 

Nedenfor er koden jeg har til nå, som ikke er synkronisert.

 

 

import java.util.PriorityQueue;
import java.util.Scanner;
class OutputVoiceThread implements Runnable
{
private String name;
private PriorityQueue<String> queue;

public OutputVoiceThread( String myName, PriorityQueue<String> queue )
{
 name = myName;
 this.queue = queue;
}

public void run()
{
 int count = 0;
 while(queue.size() != 0)
 {
  System.out.println( "Thread : " + name + ", prints : " + queue.poll() );
  count++;
 }
 System.out.println("Number of printouts from thread " + name + ": " + count);
}
}
public class threadHearUser
{
static PriorityQueue< String > queue = new PriorityQueue< String >();
static Scanner sc = new Scanner( System.in );
public static void run()
   {
 System.out.println( "****The threads want to hear the user****" );  
 System.out.println("What do you have to say?");
    userVoice( sc.nextLine() ); //Gets the input from user
    System.out.println();	
    pressAnyKey.pressAnyKey();
   }

public static void userVoice(String sentence)
   {
 queue.clear(); //Clears the queue to remove elements from last run
 String[] words = sentence.split( "\\s" );
    for( String word : words )
    {
	    queue.offer(word); //Inserts elements into priority queue
    }

    System.out.println( "Words are now added to PriorityQueue. The competition will now start.");
    pressAnyKey.pressAnyKey();

    OutputVoiceThread a = new OutputVoiceThread("A", queue );
 Thread threadA = new Thread(a);

 OutputVoiceThread b = new OutputVoiceThread("B", queue );
 Thread threadB = new Thread(b);

 OutputVoiceThread c = new OutputVoiceThread("C", queue );
 Thread threadC = new Thread(c);

 threadA.start();
 threadB.start();
 threadC.start();
   }
}

 

Lenke til kommentar
Videoannonse
Annonse

Du har en alternativ løsning, som er sinnsykt lett, men krever Java 1.6.

Collections.synchronizedCollection(din kø her) gjør at Collections rammeverket synkroniserer for deg. Du har da imidlertid kun tilgang til metodene fra Collection klassen, som er litt funksjonsfattig.

 

Måten du tenker på er også helt riktig. Bare husk at selv om du har et "guard"-objekt, som kun leverer ut køen din, betyr ikke dette at priorityqueue på magisk vis nå er synkronisert. Du må "låse" køen til en tråd er ferdig med den. Foreslår følgende:

 

private CountdownLatch lock = new CountdownLatch(0);
public Queue<String> getQueue() {
lock.await();
lock = new CountdownLatch(1);
return queue;
}
public void unlockQueue() {
lock.countDown();
}

 

En countdownLatch gir deg muligheten til å tvinge tråder til å vente til den er 0. På denne måten blokker getQueue() for alle tråder unntatt den som kalte dette først, og først når noen kaller unlockQueue(), kan andre endre. Dette er vel den løsningen jeg har sett som er mest robust og eksplisitt. I motsetning til synkronisering, gjør dette også at man kan gjøre flere ting i seriell på en tråd før andre slipper til. Men det krever litt disiplin med å kalle unlockQueue etter hver gang man er ferdig, i tillegg til at man ikke har noen garanti for at andre tråder kaller unlockQueue og "stjeler" køen som er i bruk. En fiks for dette ville vært å lagre trådnummeret til tråden som låser, og avvise forespørsler fra andre tråder om å låse opp.

Endret av Mads-b
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...