web-dev-qa-db-fra.com

exécuter 3 threads en séquence java

J'ai 3 fils 1ère impression A 2e impression B 3e impression C

Je veux imprimer en séquence A B C A B C A B C et ainsi de suite .....

J'ai donc écrit le programme ci-dessous, mais je ne parviens pas à atteindre le même objectif. Je suis conscient du problème suivant: lorsque status = 1 à ce moment-là, disons par exemple que les threads B1 et C1 sont en attente et que je notifieAll () les deux threads en attente se réveillent et, en fonction de l’allocation de l’UC, ils peuvent imprimer B ou C.

dans ce cas, je veux seulement que B soit imprimé après A.

quelle modification je dois faire.

public class NotifyAllExample {

    int status=1;
    public static void main(String[] args) {

        NotifyAllExample notifyAllExample = new NotifyAllExample();

        A1 a=new A1(notifyAllExample);
        B1 b=new B1(notifyAllExample);
        C1 c=new C1(notifyAllExample);

        a.start();
        b.start();
        c.start();
    }
}

class A1 extends Thread{
    NotifyAllExample notifyAllExample;

    A1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=1){
                        notifyAllExample.wait();
                    }

                    System.out.print("A ");
                    notifyAllExample.status = 2;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 1 :"+e.getMessage());
        }

    }

}

class B1 extends Thread{

    NotifyAllExample notifyAllExample;

    B1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=2){
                        notifyAllExample.wait();
                    }

                    System.out.print("B ");
                    notifyAllExample.status = 3;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 2 :"+e.getMessage());
        }

    }
}


class C1 extends Thread{

    NotifyAllExample notifyAllExample;

    C1(NotifyAllExample notifyAllExample){
        this.notifyAllExample = notifyAllExample;
    }

    @Override
    public void run() {

        try{
            synchronized (notifyAllExample) {

                for (int i = 0; i < 100; i++) {

                    if(notifyAllExample.status!=3){
                        notifyAllExample.wait();
                    }

                    System.out.print("C ");
                    notifyAllExample.status = 1;
                    notifyAllExample.notifyAll();
                }

            }
        }catch (Exception e) {
            System.out.println("Exception 3 :"+e.getMessage());
        }

    }
}
14
Jayesh

Convertissez ces instructions IF en instructions WHILE pour obtenir le comportement souhaité:

if (notifyAllExample.status != 2){
    notifyAllExample.wait();
}

à

while (notifyAllExample.status != 2){
    notifyAllExample.wait();
}

Cela garantira que si un thread est notifié, il ne sortira pas de la boucle while tant que la valeur de statut ne sera pas celle attendue.

En outre, marquez status comme volatile afin que les threads ne disposent pas d'une copie locale.

8
Vikdor
 public class RunThreadsInOrder implements Runnable {

    static int numThread = 1;
    static int threadAllowedToRun = 1;
    int myThreadID;
    private static Object myLock = new Object();

    public RunThreadsInOrder() {
        this.myThreadID = numThread++;
        System.out.println("Thread ID:" + myThreadID);
    }

    @Override
    public void run() {
        synchronized (myLock) {
            while (myThreadID != threadAllowedToRun) {
                try {
                    myLock.wait();
                } catch (InterruptedException e) {

                } catch (Exception e) {}
            }
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }

            System.out.println("myThreadID is running: " + myThreadID);
            myLock.notifyAll();
            threadAllowedToRun++;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Thread t1 = new Thread(new RunThreadsInOrder());
        Thread t2 = new Thread(new RunThreadsInOrder());
        Thread t3 = new Thread(new RunThreadsInOrder());
        Thread t4 = new Thread(new RunThreadsInOrder());
        Thread t5 = new Thread(new RunThreadsInOrder());
        Thread t6 = new Thread(new RunThreadsInOrder());
        Thread t7 = new Thread(new RunThreadsInOrder());

        t7.start();
        t6.start();
        t5.start();
        t4.start();
        t3.start();
        t2.start();
        t1.start();

    }
}
7
Manoj Saxena

On m'a demandé d'écrire un programme similaire dans une interview avec la condition supplémentaire qu'il soit extensible de manière à ce que nous puissions fournir notre propre nombre de threads et qu'ils impriment des caractères avec le premier thread imprimé 'A' puis les threads suivants impression B, C, D et ainsi de suite. Voici comment je l'ai fait.

public class AlternateCharPrinter {

    public static char ch = 65;

    private static void createAndStartThreads(int count) {
        Object lock = new Object();
        for (int i = 0; i < count; i++) {
            new Thread(new AlternateCharRunner((char) (65 + i), lock)).start();
        }

    }

    public static void main(String[] args) {
        createAndStartThreads(4);
    }

}

class AlternateCharRunner implements Runnable {

    private char ch;
    private Object lock;
    private static int runnerCount;

    public AlternateCharRunner(char ch, Object lock) {
        this.ch = ch;
        this.lock = lock;
        runnerCount++;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                while (ch != AlternateCharPrinter.ch) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(AlternateCharPrinter.ch++);
                if (AlternateCharPrinter.ch == (65 + runnerCount)) {
                    AlternateCharPrinter.ch = 65;
                }
                lock.notifyAll();
            }
        }
    }

}
1
Mayank Singh

Vous devez remplacer

if (notifyAllExample.status!=1)

avec

while (notifyAllExample.status!=1)

et même chose dans les 2 autres classes. Sinon, dès que l'attente se termine, le fil continue sans savoir si c'est à son tour.

0
assylias

Remplacer:

if(notifyAllExample.status!=1){
   notifyAllExample.wait();
}

avec:

while(notifyAllExample.status!=1){
   notifyAllExample.wait();
}

dans toutes les classes en conséquence.

0
Tomasz Nurkiewicz
    public class Main {
        public static void main(String[] args) throws IOException{
        Thread t1 = new Thread(new A(), "1");
        Thread t2 = new Thread(new A(), "2");
        Thread t3 = new Thread(new A(), "3");

        t1.start();
        try{
            t1.join();
        }catch (Exception e){

        }
        t2.start();
        try{
            t2.join();
        }catch (Exception e){

        }
        t3.start();
        try{
            t3.join();
        }catch (Exception e){

        }


    }
}

    class A implements Runnable{
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

ou vous pouvez utiliser Executor Framework

public class Sequence {
    int Valve = 1;
    public static void main(String[] args){
        Sequence s = new Sequence();
        ExecutorService es = Executors.newFixedThreadPool(3);

        List<Runnable> rList = new ArrayList<>();
        rList.add(new A(s));
        rList.add(new B(s));
        rList.add(new C(s));

        for(int i = 0; i < rList.size(); i++){
            es.submit(rList.get(i));
        }
        es.shutdown();

    }
}

class A implements Runnable{
    Sequence s;

    A(Sequence s){
        this.s = s;
    }

    public void run(){
        synchronized (s) {
            for (int i = 0; i < 10; i++) {
                while (s.Valve != 1) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                s.Valve = 2;
                s.notifyAll();
            }
        }
    }
}

class B implements Runnable{
    Sequence s;

    B(Sequence s){
        this.s = s;
    }

    public void run() {
        synchronized (s) {
            for (int i = 0; i < 10; i++) {
                while (s.Valve != 2) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                s.Valve = 3;
                s.notifyAll();
            }
        }
    }
}

class C implements Runnable{
    Sequence s;

    C(Sequence s){
        this.s = s;
    }

    public void run() {
        synchronized (s) {
            for(int i = 0; i < 10; i++) {
                while (s.Valve != 3) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                s.Valve = 1;
                s.notifyAll();
            }
        }
    }
}

Dans le premier cas, la jointure de chaque thread entraîne l'attente des threads. Dans le second cas, une liste stocke les threads et l'exécuteur les exécute les uns après les autres en créant 3 threads

Une autre façon de faire est d'utiliser une seule classe exécutable et de communiquer entre threads via une variable statique dans la classe principale et une variable dans la classe exécutable.

import Java.util.ArrayList;
import Java.util.List;
import Java.util.concurrent.Executor;
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;

public class Seq {
    int i = 1;
    public static void main(String[] args){
        Seq s = new Seq();
        Common c1 = new Common(s, 1);
        Common c2 = new Common(s, 2);
        Common c3 = new Common(s, 3);

        List<Runnable> l = new ArrayList<>();
        l.add(c1);
        l.add(c2);
        l.add(c3);

        ExecutorService es = Executors.newFixedThreadPool(3);
        for(int i = 0; i < 3; i++){
            es.submit(l.get(i));
        }
        es.shutdown();
    }
}

class Common implements Runnable{
    Seq s;
    int o;

    Common(Seq s, int o){
        this.s = s;
        this.o = o;
    }

    public void run(){
        synchronized (s) {
            for (int z = 0; z < 100; z++) {
                if(s.i > 3)
                    s.i = 1;
                while (s.i != o) {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(o);
                s.i++;
                s.notifyAll();
            }
        }
    }
}
0
Ameya

La solution la plus simple pour résoudre ce problème peut être la suivante:

public class PrintInOrder implements Runnable {

private int valueToPrint;
private int id;
private static int turn = 1;
private static int RESET_TURN_THRESHOLD = 3;

public PrintInOrder() {
    this.valueToPrint = -1;
}

public PrintInOrder(int id, int val) {
    this.id = id;
    this.valueToPrint = val;
}

@Override
public void run() {
        while(true) {
            if (turn == this.id) {
                System.out.println(Thread.currentThread().getName() + "::::" + valueToPrint);
                turn++;
            }
            if (turn > RESET_TURN_THRESHOLD) {
                turn = 1;
            }
        }

}

public static void main(String []args) {
    Thread t1 = new Thread(new PrintInOrder(1, 1));
    t1.setName("THREAD-1");
    t1.start();
    Thread t2 = new Thread(new PrintInOrder(2, 2));
    t2.setName("THREAD-2");
    t2.start();
    Thread t3 = new Thread(new PrintInOrder(3, 3));
    t3.setName("THREAD-3");
    t3.start();
}

}

/*
OUTPUT::::
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
THREAD-1::::1
THREAD-2::::2
THREAD-3::::3
...
*/
0
Niraj Kumar