ubuntuusers.de

Multithreading Java / Threads in bestimmter Reihenfolge

Status: Ungelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

rrDNA

Anmeldungsdatum:
21. November 2010

Beiträge: 11

Grüßt euch.

Ich habe folgendes Problem:

Ich möchte 5 Threads (a1, a2, a3, a4, a5) in Java erstellen, die in einer bestimmten Reihenfolge ablaufen sollen:

1
2
3
4
5
6

        -----> a2------
       |               |
 a1 ---------> a3 ----------> a5
       |               |
        -----> a4 -----

Dies wird meines wissens nach durch Semaphoren definiert. Leider hört da mein Wissen bereits auf, da ich selbst mich kaum mit Java befasse. Gibts da irgendeinen einfachen Trick, wie die Threads a2, a3 und a4 zuerst anfangen, sobald a1 fertig ist und ebenso a5 erst anfängt, wenn a2, a3 und a4 fertig sind?

Hier der bisherige Code:

 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

package mthreadsem;

import java.util.concurrent.Semaphore;
 
public class SemTest {
 
    public static void main(String[] args) {
        new SemTest().taskExec();
    }
    
    private void taskExec() {
        int perm = 3;
        Semaphore s = new Semaphore(perm);
       
        Tasks a1,a2,a3,a4,a5;
    
        a1 = new Tasks(s);
        a2 = new Tasks(s);
        a3 = new Tasks(s);
        a4 = new Tasks(s);
        a5 = new Tasks(s);
        
        a1.start();
        a2.start();
        a3.start();
        a4.start();
        a5.start();
 
    }
 
    class Tasks extends Thread {
        private Semaphore s3m4ph0r3;
 
        public Tasks(Semaphore s) {
            this.s3m4ph0r3 = s;
        }
       
        private void out(String s){
            System.out.println("["+System.currentTimeMillis() + "] " + getName() + ": " + s);
        }
 
        @Override
        public void run() {
            out("trying to acquire semaphore...");
 
            try {
                s3m4ph0r3.acquire();
            } catch (InterruptedException e) {
            }
 
            out("semaphore acquired successfully.");
            out("sleeping for 5s...");
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e1) {
            }
            out("woke up!");
            out("trying to release semaphore...");
 
            s3m4ph0r3.release();
 
            out("semaphore released successfully!");
            this.s3m4ph0r3 = null;
        }
    }
}

Vielen Dank für die Hilfe!

Grüße

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

rrDNA schrieb:

Dies wird meines wissens nach durch Semaphoren definiert.

Nee, die brauchst Du dafür nicht. Es reicht dafür Thread.join():

 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
package threads;

import java.util.Random;

public final class SequenceTest {

    private static final long STARTED = System.currentTimeMillis();

    private static final void log(final Object message) {
        System.out.printf("%4d %-10s %s\n", (System.currentTimeMillis() - STARTED) / 1000, Thread.currentThread()
                .getName(), message);
    }

    private static final Runnable r = new Runnable() {

        @Override
        public void run() {
            final Random rnd = new Random();
            log("Started");
            try {
                Thread.sleep(rnd.nextInt(5) * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                log("Stopped");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        final Thread a1 = new Thread(r, "a1");
        a1.start();
        a1.join();

        final Thread[] as = { new Thread(r, "a2"), new Thread(r, "a3"), new Thread(r, "a4") };

        for (final Thread t : as) {
            t.start();
        }

        for (final Thread t : as) {
            t.join();
        }

        final Thread a5 = new Thread(r, "a5");
        a5.start();
        a5.join();
    }

}

Thread a1 und Thread a5 sind natürlich etwas überflüssig hier, denn der Main-Thread wartet auf sie. Man könnte die Arbeit also auch im Main-Thread machen. Insgesamt ist das Beispiel ziemlich artifiziell und in einem Programm würde man das so wohl nicht machen.

Was willst Du denn wirklich erreichen?

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Vielleicht noch eine kleine Anmerkung zum Verhalten von join() auf Deutsch, da sich die Doku doch sehr kurz hält, was möglicherweise Unklarheiten hinterlässt, wenn man noch nicht so mit Threading vertraut ist: Ein join() auf einem bereits gestarteten Thread sorgt dafür, dass die Codeausführung des Aufrufers solange an dieser Stelle verharrt bis der entsprechende Thread fertig geworden ist (weil die Ausführung von join() halt erst dann beendet ist). Wenn auf mehrere Threads gewartet werden soll, dann macht man das - genau wie hier gezeigt - in einer Schleife. Dabei ist es ziemlich egal, ob z.B. der zweite oder der vierte Thread zuerst fertig geworden sind, denn wenn ein schon lange fertig gewordener Thread mit join() angesprochen wird, dann ist die Abarbeitung von join() nahezu sofort beendet, ohne dass wirklich auf etwas gewartet wurde. Somit ist die Zeit, die insgesamt zum Durchlaufen einer solchen Schleife benötigt wird, immer die Zeit des am längsten laufenden Threads (plus minimaler Overhead natürlich) und das ist genau das, was man in aller Regel will.

EDIT: Hier nochmal das Verhalten von join() in offiziell. 😉

Antworten |