running 3 threads in sequence java

34,319

Solution 1

Convert those IF statements to WHILE statements to get the desired behavior:

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

to

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

This will ensure that if a thread is notified, it won't go out of the while loop until the status value is what it expects.

Also, mark status as volatile so that the threads won't have a local copy.

Solution 2

 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();

    }
}

Solution 3

    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());
    }
}

or you can use 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();
            }
        }
    }
}

In the first case the join for each thread causes the threads to wait for one another. In the second case a list stores the threads and executor executes them one after another creating 3 threads

Another way to do this is where only one runnable class is present and communication between thread is done via static variable in the main class and a variable in the runnable class

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();
            }
        }
    }
}

Solution 4

I was asked to write a similar program in an interview with the added condition that it should be extensible in a way that we can provide our own count of threads and they should print characters with the first thread printing 'A' and then the subsequent threads printing B, C, D and so on. Here's how I did it.

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();
            }
        }
    }

}
Share:
34,319
Jayesh
Author by

Jayesh

Updated on May 28, 2020

Comments

  • Jayesh
    Jayesh almost 4 years

    I have 3 threads 1st printing A 2nd printing B 3rd printing C

    I want to print in sequence A B C A B C A B C and so on.....

    So I wrote the program below, but I am not able to achieve the same. I am aware of the problem that when status=1 at that time say for example B1 and C1 thread are waiting and when I do notifyAll() both waiting thread wake up and depending on CPU allocation it might print B or C.

    in this case I want only B to be printed after A.

    what modification I need to do.

    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());
            }
    
        }
    }
    
  • Jayesh
    Jayesh over 11 years
    Also, as you mentioned to mark status as volatile how it will benefit me? without marking it as volatile also I am getting desired result. theoretically I know what Volatile do but not practically....can you just explain me how java will treat status variable here without volatile and with volatile?
  • Vikdor
    Vikdor over 11 years
    without volatile keyword on status allows JVM to optimize the access to status variable by having a local copy for each thread which means writes by other threads won't be visible. Specifying the volatile keyword would prevent such optimizations and any read would get to see the value by the most recent write.
  • Jayesh
    Jayesh over 11 years
    as you mention "by having a local copy for each thread which means writes by other threads won't be visible"......if that is the case then every time update done on status variable by Thread A1/B1/C1 should be local to that thread. so when A1 changes status=2 from status=1 that will be local to A1 and B1 still has its local copy set to status=1 and it will always be in waiting state. then how it is going ahead...please clear my doubt.
  • Vikdor
    Vikdor over 11 years
    It is not guaranteed that changes to non-volatile variables are not visible across threads. It is guaranteed that changes to volatile variables are visible across threads. cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile is a good read on why volatile.
  • Jayesh
    Jayesh over 11 years
    thanks...I found some example and after running the program so many times I am able to reproduce problem of without declaring variable as Volatile.
  • Visu
    Visu almost 8 years
    can you please explain how the thread continuously run in a cyclic manner?
  • Andy Turner
    Andy Turner over 7 years
    Code dump answers are not useful to other readers because they don't explain what you have changed, or what you are trying to demonstrate. Please add explanation.
  • Michael Parker
    Michael Parker over 7 years
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. - From Review
  • Visu
    Visu over 6 years
    The idea is very simple: What is the wait condition for each thread?? For thread 2 : 1 thread should executed once before the thread 2 execute once. For thread 3 : 2 thread should executed once before the thread 3 execute once. and so on as many threads are there. For thread 2 : n thread should executed once before the thread 1 execute once. Here is the trick we should initialize as n-thread executed so the 1 - thread will start first then 2 thread and so on.
  • Harleen
    Harleen over 4 years
    Why the above solution has printed the the thread sequence 6 times?