Toon posts:

[JAVA] Thread & wait()/notify() met file read

Pagina: 1
Acties:

Onderwerpen


  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Ik ben bezig om mijn Java kennis op te vijzelen en dan met name Threads. Ik wil nu een simpele applicatie maken die twee (om te beginnen) tekst bestanden per regel uitleest waar 1 thread een tekst bestand voor zijn rekening neemt. Hieronder staan voorbeeld files met de verwachte output.

Tekstbestand 1
code:
1
2
3
4
5
file 1 - line 1
file 1 - line 2
file 1 - line 3
file 1 - line 4
file 1 - line 5


Tekstbestand 2
code:
1
2
3
4
5
file 2 - line 1
file 2 - line 2
file 2 - line 3
file 2 - line 4
file 2 - line 5


Output die ik wil
code:
1
2
3
4
5
6
7
8
9
10
file 1 - line 1
file 2 - line 1
file 1 - line 2
file 2 - line 2
file 1 - line 3
file 2 - line 3
file 1 - line 4
file 2 - line 4
file 1 - line 5
file 2 - line 5


Het gedeelte met threads is niet moeilijk, dit lukt me wel. Maar ik krijg elke keer andere output. Nu heb ik verder gezocht en ben ik op synchronized gelopen met wait() en notify(). Als ik verder zoek kom ik allemaal voorbeelden tegen, maar die hebben niks met File I/O te maken. Kan iemand mij in de juiste richting schoppen met betrekking to synchronized en het inlezen van twee files ? :)

]|[ Apple Macbook Pro Retina 13" ]|[


  • YopY
  • Registratie: September 2003
  • Laatst online: 30-05 11:31
Het lijkt mij dat je dus je bestanden tegelijkertijd (door 2 threads) wilt laten lezen en vervolgens wilt sorteren, correct? De volgorde van het lezen van de regels en het vervolgens in één lijst stoppen is niet te voorspellen, aangezien je niet kunt voorspellen wanneer je een 'context switch' krijgt, dwz wanneer thread 1 processortijd krijgt tov thread 2.

Om je basisprobleem op te lossen: laat de twee threads hun data per regel in een gedeelde / synchronized / concurrent list wegschrijven en roep daar vervolgens Collections.sort op aan, met een eigen Comparator die alleen het laatste karakter uitleest (of karakters, als er ook meercijferige cijfers in staan).

Als je het toch met threads wilt sorteren zal het eigenlijk als volgt gaan, in pseudocode.

code:
1
2
3
4
5
6
7
8
9
10
11
thread 1 {
  readline();
  thread2.notify();
  wait();
}

thread 2 {
  readline();
  thread1.notify();
  wait();
}


...Hm, ik denk dat ik je probleem begrijp. Ten eerste ben ik niet sterk in threading, heb nog nooit notify() gebruikt enzo. Ten tweede, als je notify() aanroept is het al mogelijk dat thread1 zijn bestand gaat lezen, voordat wait() aangeroepen wordt. Dat zal denk ik geen probleem zijn in dit geval, maar ik weet het niet zeker.

  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Ik wil de twee bestanden door twee verschillende threads laten uitlezen. Wat heel makkelijk is. Maar ik wil de output om en om door een thread laten outputten naar mijn console. Daar loop ik op vast.

]|[ Apple Macbook Pro Retina 13" ]|[


  • Stefan_D
  • Registratie: Oktober 2005
  • Laatst online: 23-05 14:49
Laat de Threads de regels in een Array(List?) opslaan en print dan vervolgens de ArrayLists in volgorde uit?

  • Jegorex
  • Registratie: April 2004
  • Laatst online: 11-05 20:39
DeluxZ schreef op dinsdag 14 juni 2011 @ 22:09:
Ik wil de twee bestanden door twee verschillende threads laten uitlezen. Wat heel makkelijk is. Maar ik wil de output om en om door een thread laten outputten naar mijn console. Daar loop ik op vast.
Je zult het moeten doen zoals YopY of Stefan zegt. Met alleen 2 threads zul je nooit weten wanneer welke thread actief is.
Zelf zal ik waarschijnlijk beide files naar een aparte array(list) schrijven waarna ik om en om een regel uit de array haal.

edit:
Je zult de files ook in 1 thread kunnen openen en om de beurt readline() bij file 1 en file 2 kunnen aanroepen.

[Voor 9% gewijzigd door Jegorex op 14-06-2011 22:29]


  • RobIII
  • Registratie: December 2001
  • Laatst online: 23:09

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

Woa, woa, woaaa.. Huu sik :P

Kun je me eerst eens vertellen waarom je die output precies zo wil? En waarom zou je dan twee threads willen gebruiken als je net zo makkelijk in 1 thread 2 file handles kunt openen? Ik zie dan even de toegevoegde waarde van de twee threads niet namelijk. Mocht je een goede reden voor de twee threads hebben dan ben ik nieuwschierig waarom je de regels "interleaved" wil hebben.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • Domdo
  • Registratie: Juni 2009
  • Laatst online: 04-06 15:06
Je zou ook een AtomicInteger kunnen gebruiken en elke thread een nummer te geven wanneer die aan de beurt is
Wordt dan zo iets als:
code:
1
2
3
4
5
6
7
8
sync(counter)
{
   while(counter != myNumber)
      wait()
   out(readLine)
   counter++;
   counter.notify
}

[Voor 4% gewijzigd door Domdo op 14-06-2011 22:47]


  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 05-06 08:18

CoolGamer

What is it? Dragons?

Een voordeel zou kunnen zijn dat je alvast leest, terwijl de andere thread aan het schrijven is. Dit zou een voordeel kunnen zijn wanneer de I/O traag gaat.

De code van YopY bevat de fout dat het altijd wait nadat een regel is gelezen. Hierdoor komt de thread te hangen zodra de andere thread al klaar is met lezen van het bestand. De opzet zoals gegeven door Domdo is de meest handige manier. Ook biedt de manier van Domdo de mogelijkheid om het aantal threads later uit te breiden naar meer dan twee. notify zal dan wel vervangen moeten worden naar notifyAll (notify werkt niet "fair").

Gebruiken van een AtomicInteger is niet nodig. Het gebruik van een volatile integer is voldoende. Het gebruik van de integer gebeurd al binnen een syncronized-blok, waardoor extra synchronisatie features niet nodig zijn.

[Voor 16% gewijzigd door CoolGamer op 14-06-2011 22:56]

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


  • Domdo
  • Registratie: Juni 2009
  • Laatst online: 04-06 15:06
Het probleem van een gewone Integer is dat die immutability is en dan kan je er niet meer op synchroniseren / wait/ notify want dan praat je elke keer tegen een ander object.

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 05-06 08:18

CoolGamer

What is it? Dragons?

Dat klopt, maar je zou ook een ander object kunnen gebruiken als lock. Vaak wordt er een instantie vaak Object gebruikt. Het is ook verstandig om het gelijk als final veld aan te wijzen. Anders zou het voor kunnen komen dat threads niet op hetzelfde object locken.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


  • bomberboy
  • Registratie: Mei 2007
  • Laatst online: 20:48
DeluxZ schreef op dinsdag 14 juni 2011 @ 20:57:
Ik ben bezig om mijn Java kennis op te vijzelen en dan met name Threads. Ik wil nu een simpele applicatie maken die twee (om te beginnen) tekst bestanden per regel uitleest waar 1 thread een tekst bestand voor zijn rekening neemt. Hieronder staan voorbeeld files met de verwachte output.
Ik denk dat je op zoek bent naar een Producer-Consumer model. Althans als je dit elegant wil oplossen. In dit geval heb je dan wel 2 producers (threads die lezen van files) en een extra restrictie dat je van beiden afzonderlijk de output wil volgens een bepaald patroon.
Het gedeelte met threads is niet moeilijk, dit lukt me wel. Maar ik krijg elke keer andere output. Nu heb ik verder gezocht en ben ik op synchronized gelopen met wait() en notify(). Als ik verder zoek kom ik allemaal voorbeelden tegen, maar die hebben niks met File I/O te maken. Kan iemand mij in de juiste richting schoppen met betrekking to synchronized en het inlezen van twee files ? :)
http://download.oracle.co...oncurrency/guardmeth.html
Op bovenstaande link heb je een voorbeeldje + uitleg van een mogelijke implementatie voor het implementeren van dat producer-consumer pattern in java. Ik zou suggereren dat je ook heel die trail eens doorloopt en niet enkel bovenstaande pagina.

Om jouw oplossing met interleaved tekst-output te realiseren heb je (minstens) twee mogelijkheden:
  1. Je zorgt er voor dat de producers elk om beurt een regel beschikbaar kunnen stellen. Het voordeel is dat je consumer daar dan niets hoeft van te weten.
  2. De consumer weet wel van de twee producers en zorgt er zelf voor dat de output interleaved is op de manier die jij wenst.
Beiden zijn goede oplossingen en hebben elk hun nut en voordelen/nadelen. Aangezien je diet doet als oefening kan je dan uiteraard ook gewoon beiden implementeren en vergelijken.

Qua implementatie (verder bouwend op de java tutorial) zal je het Drop-object dus moeten uitbreiden om meerdere producers te ondersteunen. Indien je kiest voor oplossing 1 moet je het Drop object en eventueel de producer aanpassen. Wanneer je kiest voor oplossing 2 moet je ook de consumer aanpassen.

  • Hydra
  • Registratie: September 2000
  • Laatst online: 03-06 17:45
bomberboy schreef op woensdag 15 juni 2011 @ 00:43:
Ik denk dat je op zoek bent naar een Producer-Consumer model. Althans als je dit elegant wil oplossen.
Ik geloof dat mensen weer veel te veel lezen in een relatief simpele vraag. De TS is 'nieuw' wat betreft threads, en heeft voor zichzelf een oefening bedacht om 2 threads om en om een simpele taak uit te laten voeren. Wat hij gewoon wil is een simpel token systeem waarbij een thread 1 regel leest als hij het token heeft, en dan het token aan de ander geeft. Het lezen uit het bestand is een randvoorwaarde die voor de synchronisatie van de threads nieteens relevant is.

https://niels.nu


  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Hydra schreef op woensdag 15 juni 2011 @ 12:05:
[...]


Ik geloof dat mensen weer veel te veel lezen in een relatief simpele vraag. De TS is 'nieuw' wat betreft threads, en heeft voor zichzelf een oefening bedacht om 2 threads om en om een simpele taak uit te laten voeren. Wat hij gewoon wil is een simpel token systeem waarbij een thread 1 regel leest als hij het token heeft, en dan het token aan de ander geeft. Het lezen uit het bestand is een randvoorwaarde die voor de synchronisatie van de threads nieteens relevant is.
Juist. Ik ben op het moment bezig om per Thread de file per regel in een arraylist te stoppen en deze dan om en om een item uit de arraylist te laten printen (interleaved). Eigenlijk wou ik dit niet gaan doen, zou je een voorbeeld kunnen geven met het token idee?

]|[ Apple Macbook Pro Retina 13" ]|[


  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 05-06 08:18

CoolGamer

What is it? Dragons?

Voorbeeld met token(current):
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.io.*;

public class Main implements Runnable {

    public static void main(String[] args) throws Exception {
        Thread thread1 = new Thread(new Main("file1.txt", 0, 1));
        Thread thread2 = new Thread(new Main("file2.txt", 1, 0));
        
        thread1.start();
        thread2.start();
        
        thread1.join();
        thread2.join();
        System.out.println("Finished");
    }
    
    private static final Object lock = new Object();
    private static volatile int current = 0;        
    private BufferedReader in;
    private int me, next;
    
    public Main(String file, int me, int next) throws IOException {
        in = new BufferedReader(new FileReader(file));
        this.me = me;
        this.next = next;
    }
    
    @Override
    public void run() {
        String line;
        try {
            while ((line = in.readLine()) != null) {
                synchronized (lock) {
                    while (me != current) {
                        lock.wait();
                    }
                
                    System.out.println(line);
                    current = next;
                    lock.notifyAll();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    
}

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


  • Dricus
  • Registratie: Februari 2002
  • Laatst online: 18:05

Dricus

ils sont fous, ces tweakers

Uit de OP begrijp ik dat TS graag zijn kennis op wil vijzelen. Vandaar dat ik even de vrijheid neem om hier wat kennis over Java threading te dumpen ;). Threading in Java is een vrij lastig onderwerp omdat de Java specificatie een aantal aspecten expliciet overlaat aan JVM bouwers.

Voorbeeld: Je gebruikt één object die door beide threads gebruikt wordt voor wait/notify:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
final Object mutex = new Object();

Runnable runnable1 = new Runnable() {
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (mutex) {
                // Wacht tot thread 2 klaar is
                try {
                    mutex.wait();
                } catch (InterruptedException e) {
                }

                // Lees 1 regel uit input bestand
                System.out.println("Tread 1 " + i);

                // Verwittig thread 2 dat hij mag
                mutex.notify();
            }
        }
    }
};

Runnable runnable2 = new Runnable() {
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (mutex) {
                // Lees 1 regel uit input
                System.out.println("Tread 2 " + i);

                // Verwittig thread 1 dat hij mag
                mutex.notify();
                
                // Wacht tot thread 1 klaar is
                try {
                    mutex.wait();
                } catch (InterruptedException e) {
                }
            }
        }
    }
};

Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);

thread1.start();
thread2.start();

Ziet er op het eerste gezicht leuk uit, en er is een goede kans dat dit ook wel gaat werken (als ik deze code draai, dan werkt het; de threads geven netjes om en om een melding op het scherm). Toch is er een catch: Dit werkt alléén als thread1 ook daadwerkelijk eerder start dan thread2. Als dit niet het geval is, dan zal thread1 pas bij de mutex.wait() aankomen als thread2 ook bij de mutex.wait() is aangekomen. Op dat moment staan beide threads dus te wachten op een mutex.notify() die nooit komt.

Nu denk je misschien nog steeds: Wat is nou het probleem? Je start thread1 toch het eerst?

Dan nu de échte catch: De Java specificatie schrijft niet voor dat de thread die het eerst gestart wordt ook daadwerkelijk het eerst begint te lopen. Het starten van een Java thread is (puur vanuit Java perspectief gezien) niets meer dan het in de Runnable state zetten van een thread. Of en zo ja wanneer de thread daadwerkelijk CPU tijd krijgt (in de Running state geplaatst wordt) is afhankelijk van de JVM implementatie die je gebruikt.

Ondanks dat thread1 in mijn voorbeeld dus eerder wordt gestart dan thread2 kan het zo zijn dat thread2 eerder begint te lopen dan thread1. Je kunt in het bovenstaande voorbeeld niet van tevoren voor 100% garanderen dat thread1 in alle situaties, met alle JVM's op alle platforms altijd als eerste start.

Als je serieus met Java en threading bezig wilt gaan, dan moet je één regel altijd goed in het achterhoofd houden:
quote: Kathy Sierra in haar SCJP study guide
When it comes to threads, very little is guaranteed.
Mijn oplossing zou zijn om beide threads elke regel naar een eigen Queue<String> te laten schrijven. Vervolgens kun je in de main thread (of in een derde thread) beide queues om en om uitlezen om het gewenste resultaat te bereiken.

Edit: Of natuurlijk zoals hierboven met een token werken.

Stel niet uit tot morgen wat je vandaag nog tot morgen kunt uitstellen...


  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
@Dricus: Bedankt voor je uitleg. Ik ben niet helemaal nieuw met Threads maar het is al een tijd geleden dat ik er iets mee gedaan heb :)

@TheCoolGamer: Ik zal het is gaan uitproberen :)

Ik heb het nu gedaan zoals eerder al gezegd werd met een ArrayList en per thread per file alles in een arraylist zetten en om en om laten printen uit de ArrayList. Het is niet precies zoals ik wou, maar het werkt. Ga nu nog is bovenstaande proberen :)

]|[ Apple Macbook Pro Retina 13" ]|[


  • JaWi
  • Registratie: Maart 2003
  • Laatst online: 10-04 18:12

JaWi

maak het maar stuk hoor...

Dricus schreef op woensdag 15 juni 2011 @ 15:26:
(een goede post over Threading)
Goed voorbeeld; alleen zou ik de TS nog als advies willen meegeven dat je nooit een InterruptedException moet negeren. Zie bijv. deze tutorial en deze newsletter waarom niet...

@TS: kijk wel uit met een ArrayList als je deze vanuit meerdere threads gaat muteren, aangezien deze niet gesynchroniseerd is. Een Vector of een CopyOnWriteArrayList is een goed alternatief met dezelfde interface...

[Voor 19% gewijzigd door JaWi op 16-06-2011 08:33. Reden: Nog een tip voor de TS...]

Statistics are like bikinis. What they reveal is suggestive, but what they hide is vital.


  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
DeluxZ schreef op woensdag 15 juni 2011 @ 19:23:
@Dricus: Bedankt voor je uitleg. Ik ben niet helemaal nieuw met Threads maar het is al een tijd geleden dat ik er iets mee gedaan heb :)

@TheCoolGamer: Ik zal het is gaan uitproberen :)

Ik heb het nu gedaan zoals eerder al gezegd werd met een ArrayList en per thread per file alles in een arraylist zetten en om en om laten printen uit de ArrayList. Het is niet precies zoals ik wou, maar het werkt. Ga nu nog is bovenstaande proberen :)
De methode van TheCoolGamer werkt goed, áls de bestanden allemaal even groot zijn qua regels. Op dit moment heb ik 3 files. De eerste is 5 regels lang, de tweede 10 en de derde 15. Nu krijg ik de volgende output:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
file 1 - line 1 verwerkt door: Thread-1
file 2 - line 1 verwerkt door: Thread-2
file 3 - line 1 verwerkt door: Thread-3
file 1 - line 2 verwerkt door: Thread-1
file 2 - line 2 verwerkt door: Thread-2
file 3 - line 2 verwerkt door: Thread-3
file 1 - line 3 verwerkt door: Thread-1
file 2 - line 3 verwerkt door: Thread-2
file 3 - line 3 verwerkt door: Thread-3
file 1 - line 4 verwerkt door: Thread-1
file 2 - line 4 verwerkt door: Thread-2
file 3 - line 4 verwerkt door: Thread-3
file 1 - line 5 verwerkt door: Thread-1
file 2 - line 5 verwerkt door: Thread-2
file 3 - line 5 verwerkt door: Thread-3


Thread-1 is gekilled nadat line == null.

Hoe kan ik dit oplossen?

]|[ Apple Macbook Pro Retina 13" ]|[


  • Jegorex
  • Registratie: April 2004
  • Laatst online: 11-05 20:39
Wat moet er opgelost worden?
Na 5 regels zal file1 null returnen omdat alle regels gelezen zijn. Thread1 zal dan stoppen als het goed is terwijl threads 2 en 3 doorgaan.

  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Klopt, threads 2 en 3 gaan door maar ze printen niks meer

]|[ Apple Macbook Pro Retina 13" ]|[


  • Jegorex
  • Registratie: April 2004
  • Laatst online: 11-05 20:39
In thread 3 doe je een notify naar thread 1 en in thread 1 doe je een notify naar thread 2?
Als dat het geval is zit daar je fout, thread 3 roept thread 1 aan, maar thread 1 doet niks omdat die al klaar is.

  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Ik heb ondertussen opgelost dat het printen doorgaat. Maar nu blijven de threads altijd 'alive'. Dit wil je natuurlijk niet. Hoe zou ik kunnen checken of alle 3 de files gelezen zijn ?

Ik heb op dit moment de volgende code:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Main implements Runnable {

    public static void main(String[] args) throws Exception {
        Thread thread1 = new Thread(new Main("file1.txt", 0, 1));
        Thread thread2 = new Thread(new Main("file2.txt", 1, 2));
        Thread thread3 = new Thread(new Main("file3.txt", 2, 0));

        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
    }
    
    private static final Object lock = new Object();
    private static int current = 0;
    private BufferedReader in;
    private int me, next;

    public Main(String file, int me, int next) throws IOException {
        this.in = new BufferedReader(new FileReader(file));
        this.me = me;
        this.next = next;
    }

    @Override
    public void run() {
        String line;    
        try {
            while (true) {
                synchronized (lock) {    
            while (me != current) {
                        lock.wait();
                    }
            
            line = in.readLine();
            if(line != null){           
            System.out.println(line + " verwerkt door: " + Thread.currentThread().getName());   
            }
            
                    current = next;
            lock.notifyAll();           
                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}

]|[ Apple Macbook Pro Retina 13" ]|[


  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Zodra readLine() null leest, is het einde van de file bereikt. Je zult dus óf voor iedere thread bij moeten houden of deze klaar is met lezen en stoppen als dit voor alle threads gebeurd is (wat niet echt schaalbaar is), óf je moet de beurt doorgeven op een andere manier implementeren.
Denk dan bijvoorbeeld aan het gebruik van een (ordered) list met tokens (één voor iedere Thread) waarbij een thread zichzelf verwijdert uit de lijst als hij het einde van de file bereikt heeft. Voor het doorgeven van de beurt zoekt iedere Thread de volgende in de list, tenzij het de laatste is, dan wordt de eerste van de list doorgegeven.

Denk dan aan iets als:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
while(true) {
    synchronized(lock) {
        while(me != current) {
            lock.wait();
        }
        int nextPosition = tokenList.indexOf(me) + 1;
        current = tokenList.get(nextPosition < tokenList.size() ? nextPosition : 0);
        try {
            line  = in.readLine();
            if (line != null) {
                System.out.println(line + " verwerkt door: " + Thread.currentThread().getName());
            } else {
                tokenList.remove(me);
                break;
            }
        } finally {
            lock.notifyAll();
        }
    }
}

NB: Hierbij moeten de Tokens wel vervangen door objecten, en in de juiste volgorde in een List opgenomen worden.

  • DeluxZ
  • Registratie: Augustus 2003
  • Laatst online: 02-06 17:25

DeluxZ

Livin' the good life

Topicstarter
Bedankt voor je antwoord. Het is inmiddels gelukt.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class Main implements Runnable {
    
    private static List<Object> tokenList = new ArrayList<Object>(3);
    
    private static final Object lock = new Object();
    private static Object current = 0;
    private BufferedReader in;
    private Object me;

    public static void main(String[] args) throws Exception {
    
    Thread thread1 = new Thread(new Main("file1.txt", 0));
    Thread thread2 = new Thread(new Main("file2.txt", 1));
    Thread thread3 = new Thread(new Main("file3.txt", 2));
    
    tokenList.add(0);
    tokenList.add(1);
    tokenList.add(2);

    thread1.start();
    thread2.start();
    thread3.start();

    thread1.join();
    thread2.join();
    thread3.join();
    
    }

    public Main(String file, int me) throws IOException {
    this.in = new BufferedReader(new FileReader(file));
    this.me = me;
    }

    @Override
    public void run() {
    String line;

    try {
        while (true) {
        synchronized (lock) {
            
            while (me != current) {
            lock.wait();
            }
            
            int nextPosition = tokenList.indexOf(me) + 1;
            current = tokenList.get(nextPosition < tokenList.size() ? nextPosition : 0);
            
            try {
            line = in.readLine();
            if (line != null) {
                System.out.println(line + " verwerkt door: " + Thread.currentThread().getName());
            } else {
                tokenList.remove(me);
                break;
            }
            } finally {
            lock.notifyAll();
            }
            
        }
        }
    } catch (InterruptedException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }

    }
}

]|[ Apple Macbook Pro Retina 13" ]|[


  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
Over het algemeen zou je threads niet hoeven laten wachten. In dit specifieke geval zou je dit zelfs nooit met threads oplossen omdat het simpelweg traag is om de threads op elkaar te laten wachten.

Stiekem gebruik je nu namelijk nog steeds maar 1 thread tegelijk, maar dan heb je wel de overhead van 3 threads (bij 3 files that is).

Ik snap dat dit handig is om threads te leren, maar op het moment dat je waits en notify's gebruikt krijg je ook kansen op deadlocks en alle ellende die daarbij komt kijken. Ik zeg niet dat ze evil zijn, maar ik vermijd ze toch liever als het kan.

Dus mocht je serieus dit specifieke probleem op willen lossen:
1) Lees de files in in threads (vraag me af of dit sneller is, de HD is hier namelijk de bottleneck);
2) Gooi ze allemaal in dezelfde sortedlist;
3) Done :)

Als het gaat om een server applicatie die je wilt opdelen in meerdere processen, neem dan eens een kijkje bij zeromq: http://www.zeromq.org/

Het mooie aan dit systeem is dat je, je processen zonder moeite naar andere servers kan verplaatsen of kunt opschalen.

  • Jegorex
  • Registratie: April 2004
  • Laatst online: 11-05 20:39
Je gebruikt voor elke thread dezelfde lock, daardoor zal je thread aldoor bij regel 41 wachten ipv bij regel 44.
Verder zou ik de readline voor de wait plaatsen. Dan wordt de regel ingelezen terwijl de andere threads bezig zijn met het verwerken van hun regel en zal de wachttijd tussen de verschillende threads korter worden.

  • Remus
  • Registratie: Juli 2000
  • Laatst online: 15-08-2021
Jegorex schreef op dinsdag 18 oktober 2011 @ 13:21:
Je gebruikt voor elke thread dezelfde lock, daardoor zal je thread aldoor bij regel 41 wachten ipv bij regel 44.
Verder zou ik de readline voor de wait plaatsen. Dan wordt de regel ingelezen terwijl de andere threads bezig zijn met het verwerken van hun regel en zal de wachttijd tussen de verschillende threads korter worden.
Hoewel dit een zeer synthetisch geval is, is het hier echt wel nodig dat ze op dezelfde monitor synchroniseren, anders is er geen happens-before relatie met wat de andere threads doen. Realiseer je ook dat een wait() call een Thread parkeert en de monitor released zolang de Thread wacht.

Verder is er geen garantie van de volgorde waarop threads als eerste het synchronized block in gaan, als Thread 1 voor Thread 2 en 3 gaat dan wachten Thread 2 en 3 inderdaad op het synchronized block, als thread 2 of 3 echter eerst zijn, zullen ze het synchronized block in gaan en vervolgens de wait condition bereiken, waarna thread 1 wel voortgang heeft (want de current thread).
Pagina: 1


Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee