Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Threads: How to print alphabets and numbers using two threads one at a time

I am trying to work around with threads in java. Though I understand that threads output are unpredictable, However was wondering if there is a way to do that.

I have to implement two threads, one prints alphabets(a,b,c...z) and other prints numbers(1,2,3....26). Have to implement it in such a way that the output should be a,1,b,2,c,3,d,4......z,26. Below is my code but it doesn't give the desired output.

public class ThreadsExample {

  public static void main(String[] args) {
    Runnable r = new Runnable1();
    Thread t = new Thread(r);
    Runnable r2 = new Runnable2();
    Thread t2 = new Thread(r2);
    t.start();
    t2.start();
  }
}

class Runnable2 implements Runnable{
  public void run(){
    for(char i='a';i<='z';i++) {
        System.out.print(i+",");
    }
  }
}

 class Runnable1 implements Runnable{
  public void run(){
    for(int i=1;i<=26;i++) {
       System.out.print(i+",");
    }
 }
}

What tweak should I make in the code to get the desired output? How does synchronization helps here? Or is it really possible when working with Threads at all?

PS: This is not an assignment or some exercise. Its self learning.

like image 227
roger_that Avatar asked Aug 17 '17 11:08

roger_that


3 Answers

It is possible. You need to synchronize it well.

Approach Pseudocode

query some (synchronized) state state will tell whether nums or chars are allowed

if state allows char and caller will put chars, do it now and change state and wake up waiting threads

if not, wait

if state allows numbers and caller will put numbers, do it now and change state and wake up waiting threads

if not, wait

Java code

public class ThreadsExample {
  public static ThreadsExample output = new ThreadsExample ();

  public static void main(String[] args) {
    Runnable r = new Runnable1();
    Thread t = new Thread(r);
    Runnable r2 = new Runnable2();
    Thread t2 = new Thread(r2);
    t.start();
    t2.start();
  }

  private Object syncher = new Object ();  // we use an explicit synch Object, you could use annotation on methods, too. like ABHISHEK did.
             // explicit allows to deal with more complex situations, especially you could have more the one locking Object
  private int state = 0; // 0 allows chars, 1 allows ints

  public void print (char pChar) {
    synchronized (syncher) {      // prevent the other print to access state
        while (true) {
            if (state == 0) {     // char are allowed
                System.out.print(pChar + ","); // print it
                state = 1;        // now allow ints
                syncher.notify(); // wake up all waiting threads
                return;
            } else {              // not allowed for now
                try {
                    syncher.wait();  // wait on wake up
                } catch (InterruptedException e) {
                }
            }
        }
    }
  }

  public void print (int pInt) {
    synchronized (syncher) {
        while (true) {
            if (state == 1) {
                System.out.print(pInt + ",");
                state = 0;
                syncher.notify();
                return;
            } else {
                try {
                    syncher.wait();
                } catch (InterruptedException e) {
                }
            }
        }
     }
  }
}

class Runnable2 implements Runnable{
  public void run(){
    for(char i='a';i<='z';i++) {
        ThreadsExample.output.print(i);
    }
  }
}

 class Runnable1 implements Runnable{
  public void run(){
    for(int i=1;i<=26;i++) {
        ThreadsExample.output.print(i);
    }
 }
}

Output

a,1,b,2,c,3,d,4,e,5,f,6,g,7,h,8,i,9,j,10,k,11,l,12,m,13,n,14,o,15,p,16,q,17,r,18,s,19,t,20,u,21,v,22,w,23,x,24,y,25,z,26,

like image 173
stefan bachert Avatar answered Oct 19 '22 01:10

stefan bachert


The whole idea of threads: it represents a "stream of activity" that executes code independent of other threads.

In your case, you want that these two threads go in "lockstep". Thread A does one step, then Thread B, then A, then B.

In order to get there, the two threads need something "synchronize" on - in other words: A sends a signal to B when it has done its steps - and B has to wait for that signal. Then B does its thing, signals to A, ...

For starters, a simple boolean value would do. One thread sets it to true, the other to false (to indicate when it has made its step). Then the thread waits for the boolean to toggle again.

As you intend to learn things, I would just start experimenting from there. In case you want to take detours, look here for example. This might help as well.

like image 3
GhostCat Avatar answered Oct 19 '22 01:10

GhostCat


HERE IS THE CODE:: You need to create 2 threads and implement wait and notify methods correctly you can also refer "Create two threads, one display odd & other even numbers" for your answer.

    public class ThreadClass {
    volatile int i = 1;
    volatile Character c = 'a';
    volatile boolean state = true;

    synchronized public void printAlphabet() {
        try {
            while (!state) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " " +c);
        state = false;
        c++;
        notifyAll();
    }
    synchronized public void printNumbers() {
        try {
            while (state) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " " + i);
        state = true;
        i++;
        notifyAll();
    }
    public static void main(String[] args) {
        ThreadClass threadClass = new ThreadClass();
        Thread t1 = new Thread() {
            int k = 0;
            @Override
            public void run() {
                while (k < 26) {
                    threadClass.printAlphabet();
                    k++;
                }
            }
        };
        t1.setName("Thread1");
        Thread t2 = new Thread() {
            int j = 0;

            @Override
            public void run() {
                while (j < 26) {
                    threadClass.printNumbers();
                    j++;
                }
            }
        };
        t2.setName("Thread2");

        t1.start();

        t2.start();
    }
}
like image 2
Abhishek Honey Avatar answered Oct 19 '22 01:10

Abhishek Honey