Using multiple threads to print statements sequentially

8.3k views Asked by At

I am trying to print numbers from 1 to 10 using three threads. thread 1 prints 1, 2 prints 2, 3 prints 3, 4 is printed by thread 1 again and so on.

I have created a shared printer resource that helps those threads to print number. But I am getting confused as how can i make the number to be visible by all threads.

The problem is eachthread is seeing their own copy of number while I need the same number to be shared by all threads.

I am trying to create this example for learning purposes. I have seen other pages on SO that had same kind of problem but I am not able to get the concept.

Any help is appreciated.

how is this example diffrent from what I am doing? Printing Even and Odd using two Threads in Java

public class PrintAlternateNumber {


    public static void main(String args[]) {

        SharedPrinter printer = new SharedPrinter();

        Thread t1 = new Thread(new myRunnable2(printer,10,1),"1");
        Thread t2 = new Thread(new myRunnable2(printer,10,2),"2");
        Thread t3 = new Thread(new myRunnable2(printer,10,3),"3");

        t1.start();
        t2.start();
        t3.start();     
    }
}

class myRunnable2 implements Runnable {

    int max;
    SharedPrinter printer;
    int threadNumber;

    int number=1;

    myRunnable2(SharedPrinter printer,int max,int threadNumber) {
        this.max=max;
        this.printer=printer;
        this.threadNumber=threadNumber;
    }

    @Override
    public void run() {
        System.out.println(" The thread that just entered run "+ Thread.currentThread().getName());     
        for(int i =1;i<max;i++){
            try {
                printer.print(i,threadNumber);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}


class SharedPrinter {

    boolean canPrintFlag=false;


    public synchronized void print(int number,int threadNumber) throws InterruptedException{

        if(number%3==threadNumber) {
            canPrintFlag=true;
        }

        while(!canPrintFlag)
        {
            System.out.println(Thread.currentThread().getName() + " is waiting as it cannot print " + number);
            wait();


        }
        System.out.println(Thread.currentThread().getName()+" printed "+number);
        canPrintFlag=false;
        notifyAll();



    }
}

//output
 //The thread that just entered run 2
// The thread that just entered run 3
 //The thread that just entered run 1
//3 is waiting as it cannot print 1
//1 printed 1
//1 is waiting as it cannot print 2
//3 is waiting as it cannot print 1
//2 is waiting as it cannot print 1

Technique second

it is still incomplete but I am close

output

0printed by0 2printed by2 1printed by1

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

class AlternateNumber {

    public static void main(String args[]) {

        printerHell ph = new printerHell();
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);     
        for(int i=0;i<10;i++)
        {
            queue.add(i);
        }

        Thread t1 = new Thread(new myRunnableHell(queue,0,ph),"0");
        Thread t2 = new Thread(new myRunnableHell(queue,1,ph),"1");
        Thread t3 = new Thread(new myRunnableHell(queue,2,ph),"2");

        t1.start();
        t2.start();
        t3.start();     
    }

}

class myRunnableHell implements Runnable {

    BlockingQueue<Integer> queue;   
    int threadNumber;
    printerHell ph;

    myRunnableHell(BlockingQueue<Integer> queue, int threadNumber,printerHell ph) {

        this.queue=queue;       
        this.threadNumber=threadNumber;
        this.ph=ph;
    };

    int currentNumber;

    @Override
    public void run() {

        for(int i=0;i<queue.size();i++)
        {
            currentNumber=queue.remove();

            if(threadNumber%3==currentNumber) 
            {
                ph.print(currentNumber);
            }   

        }   

    }   

}

class printerHell {

    public synchronized void print(int Number)
    {
        System.out.println(Number + "printed by" + Thread.currentThread().getName());
    }


}
2

There are 2 answers

2
superfuzzy On

I hope I understood you right, but there are to main "features" in java to make a variable being shared between threads:

  • the volatile keyword

    volatile int number = 1;

  • AtomicInteger (a standard java class -> no library)

    AtomicInteger number = new AtomicInteger(1);

These two techniques should both do what you want, however I have no experience using it, I just came upon this word, didn't know what it means and did some digging.

Some stuff to read: ;)

volatile for java explained --> http://java.dzone.com/articles/java-volatile-keyword-0

a better explanation (with IMAGES!!) but for c# (which is still the same usage) --> http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

And a link to some usages of AtomicInteger --> https://stackoverflow.com/a/4818753/4986655

I hope I could help you or at least send you in the right direction :)
- superfuzzy

0
Kalyan Chakravarthi On

Please see my solution here..

Using simple wait/notify https://stackoverflow.com/a/31668619/1044396

Using cyclic barriers: https://stackoverflow.com/a/23752952/1044396

For your query on 'How different it is from even/odd thread problem. --> it is almost same ... instead of maintaining two states have one more state to call the third thread, so I believe,this can be extended any number of threads.

EDIT:

You may view this approach when you want to have 'n' number of threads to do the work sequentially.(Instead of having different classes t1,t2,t3 etc)

https://codereview.stackexchange.com/a/98305/78940

EDIT2: Copying the code here again for the above solution

I tried to solve using a single class 'Thrd' which gets initialized with its starting number.

ThreadConfig class which as size of total number of threads you want to create.

State class which maintains the state of the previous thread.(to maintain ordering)

Here you go..(please review and let me know your views)

EDIT: How it works -->

when a thread Tx gets a chance to execute.. it will set state variable's state with x. So a next thread(Tx+1) waiting , will get a chance once state gets updated. This way you can maintain the ordering of threads.

I hope i am able to explain the code. Please run it and see or let me know for any specific queries on the below code

1) package com.kalyan.concurrency;

    public class ThreadConfig {

        public static final int size = 5;

    }

2) package com.kalyan.concurrency;

    public class State {

      private volatile int state ;

        public State() {
            this.state =3;
        }

        public State(int state) {
            this.state = state;
        }

        public  int getState() {
            return state;
        }

        public  void setState(int state) {
            this.state = state;
        }


    }

3) package com.kalyan.concurrency;

        public class Thrd implements Runnable {

            int i ;
            int name;
            int prevThread;
            State s;
            public Thrd(int i,State s) {
                this.i=i;
                this.name=i;
                this.prevThread=i-1;
                if(prevThread == 0) prevThread=ThreadConfig.size;
                this.s=s;
            }

            @Override
            public void run() {


                while(i<50)
                {
                    synchronized(s)
                      {
                          while(s.getState() != prevThread)
                          {


                                  try {
                                    s.wait();
                                } catch (InterruptedException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                              }

                          } 

                              synchronized(s)
                              {
                               //if(s.getState() ==3)

                              if(s.getState()==prevThread)
                               System.out.println("t"+ name+ i);
                               s.setState(name);
                                   i = i +ThreadConfig.size ;
                              s.notifyAll();


                             }   
                }

            }

        }

4) package com.kalyan.concurrency;

        public class T1t2t3 {
        public static void main(String[] args) {

            State s = new State(ThreadConfig.size);


            for(int i=1;i<=ThreadConfig.size;i++)
            {
                Thread T = new Thread(new Thrd(i,s));   
                T.start();

            }



        }
        }

OUTPUT:

 t11
 t22
 t33
 t44
 t55
 t16
 t27
 t38
 t49
 t510
 t111
 t212
 t313
 t414
 t515
 t116..............