简体   繁体   中英

Writing a program with 2 threads which prints alternatively

I got asked this question recently in an interview.

Write a program with two threads (A and B), where A prints 1 , B prints 2 and so on until 50 is reached.

How do we go about doing that ?

The essence of the assignment is to demonstrate how a thread can signal another one. Most common way is to use blocking queues, but here a signal does not carry any information, so a Semaphore is sufficient.

Create thread class which is parameterized with 2 Semaphores: input and output:

class ThreadPrinter implements Runnable {
    int counter;
    Semaphore ins, outs;

    ThreadPrinter(int counter, Semaphore ins, Semaphore outs) {
        this.counter = counter;
        this.ins = ins;
        this.outs = outs;
    }

    @Override
    public void run() {
        for (int i = 0; i < 25; i++) {
            ins.aquire(); // wait for permission to run
            System.out.println("" + counter);
            outs.release();  // allow another thread to run
            counter += 2;
        }
    }

Create 2 Semaphore s and pass them to 2 threads:

Semaphore a = new Semaphore(1);  // first thread is allowed to run immediately
Semaphore b = new Semaphore(0); // second thread has to wait
ThreadPrinter tp1 = new ThreadPrinter(1, a, b);
ThreadPrinter tp2 = new ThreadPrinter(2, b, a); 

Note semaphores a and b are passed in different order.

public class Test {

private static int count = 0;

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {

            for (int i = 0; i < 25; i++) {
                synchronized (CommonUtil.mLock) {
                    incrementCount();
                    CommonUtil.mLock.notify();
                    try {
                        CommonUtil.mLock.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    });
    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {

            for (int i = 0; i < 25; i++) {
                synchronized (CommonUtil.mLock) {
                    incrementCount();
                    CommonUtil.mLock.notify();
                    try {
                        CommonUtil.mLock.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    });
    t1.start();
    Thread.sleep(400);
    t2.start();
    t1.join();
    t2.join();
}

private static void incrementCount() {

    count++;
    System.out.println("Count: " + count + " icnremented by: " +        Thread.currentThread().getName());
}
}
  class CommonUtil {

 static final Object mLock = new Object();
   }

I encountered the same problem and was expected to use only basics so I choose wait notify on shared object between threads

public class Message implements Runnable {

    private static final int N = 10;
    private Thread thread;
    private static Object object = new Object();

    public Message(String name){
        thread = new Thread(this, name);
        thread.start();
    }

    public void run(){
        for(int i=0; i<N; i++){
            synchronized (object) {
                System.out.println(i + "--" + thread.getName());
                object.notify();
                try {
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}

In main method :

Message message1 = new Message("Ping");
Message message2 = new Message("Pong");

hi please find answer here...pattern ABABABAB

package com.abhi.ThreadPractice;

    public class Test {

        public static void main(String[] args) throws InterruptedException {

          final Object lock = new Object();
          Thread t1 = new Thread(new Runnable() {

            @Override
           public void run() {
            for (int i = 0; i < 10; i++) {

              synchronized (lock) {
             // count++;
              System.out.println("A");
              try {
               lock.wait();
               lock.notify();
              } catch (InterruptedException e) {
               e.printStackTrace();
              }
             }
            }
           }
          });             

           Thread t2 = new Thread(new Runnable() {

            @Override
           public void run() {
            for (int i = 0; i < 10; i++) {
             synchronized (lock) {
              lock.notify();
              //count++;
              System.out.println("B");
              try {
               lock.wait();
              } catch (InterruptedException e) {
               e.printStackTrace();
              }
             }
            }
           }
          });

           t1.start();
          t2.start();
          t1.join();
          t2.join();

          }

        }

May be this is still relevant:

public class MyRunnable implements Runnable {
    public static int counter = 0;
    public static int turn = 0;
    public static Object lock = new Object();

    @Override
    public void run() {
        while (counter < 50) {
            synchronized (lock) {
                if (turn == 0) {

                    System.out.println(counter + " from thread "
                            + Thread.currentThread().getName());
                    turn = 1;
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                } else {
                    turn = 0;
                    lock.notify();
                }

            }
        }
    }
}

and then the main function

public static void main(String[] args) {
        Thread threadA = new Thread(new MyRunnable());
        Thread threadB = new Thread(new MyRunnable ());
        threadA.start();
        threadB.start();
}
public class PingPong extends Thread {
static StringBuilder object = new StringBuilder("");

public static void main(String[] args) throws InterruptedException {

    Thread t1 = new PingPong();
    Thread t2 = new PingPong();

    t1.setName("\nping");
    t2.setName(" pong");

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

@Override
public void run() {
    working();
}

void working() {
    while (true) {
        synchronized (object) {
            try {
                System.out.print(Thread.currentThread().getName());
                object.notify();
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

}

public class ThreadCounter implements Runnable {
    private static int count = 0;

    private Thread t;

    public ThreadCounter(String tName){
        t= new Thread(this, tName);
        t.start();
    }

    @Override
    public void run() {
        for(int i=1; i<=5; i++){
            synchronized (CommonUtil.mLock) {
                incrementCount(t.getName());
                CommonUtil.mLock.notify();
                try {
                    CommonUtil.mLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void incrementCount(String tName){
        System.out.println(tName+": "+(++ThreadCounter.count));
    }

    public static void main(String[] args) throws InterruptedException {
        new ThreadCounter("Thread1");
        Thread.sleep(500);
        new ThreadCounter("Thread2");
    }

}

class CommonUtil{
    public static Object mLock = new Object();
}

This was the simplest solution, I was able to think of. It uses a synchronized method and uses the notify() and the wait() to alternatively print the numbers. Hope it helps. :)

 public class program implements Runnable
    {
        static int count =1;
        private static final int MAX_COUNT = 50;
        public synchronized void print ()
        {
            System.out.println(Thread.currentThread().getName() + " is printing " + count);
            count++;
            notify();
            try{
                if(count>MAX_COUNT)
                    return;
                wait();
            }catch (InterruptedException e){ 
                e.printStackTrace();
            }
        }
        public void run()
        {
            for(int i=0;i<MAX_COUNT/2;i++)
            {
                print();

            }
        }

        public static void main(String[] args) {

            program x= new program();
            Thread t0= new Thread(x);
            Thread t1=  new Thread(x);
            t0.start();
            try
            {
                Thread.sleep(1);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
            t1.start();     
        }


    }
//simply use wait and notify and and set a counter and it will do  

public class ThreadalternatePrint implements Runnable {
    static int counter =0; 
    @Override
    public synchronized void run() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        while(counter<51)
        {   ++counter;
        notify();
        System.out.println(Thread.currentThread().getName());
            try {
                    wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }       
    }

    public static void main(String[] args) {
        ThreadalternatePrint obj1 = new ThreadalternatePrint();
        Thread Th1 = new Thread(obj1);
        Thread Th2 = new Thread(obj1);
        Th1.setName("Thread1");
        Th2.setName("Thread2");
        Th1.start();
        Th2.start();
    }


}
public class Testing implements Runnable {
private static int counter = 1;
private static final Object lock = new Object();

public static void main(String[] args)  {

    Thread t1 = new Thread(new Testing(), "1");
    t1.start();
    Thread t2 = new Thread(new Testing(), "2");
    t2.start();

}

@Override
public void run() {
    while (counter<=100) {
        synchronized (lock) {
            if (counter % 2 == 0) {
                System.out.println(counter +" Written By Thread-"+ Thread.currentThread().getName());
                counter++;
                try {
                    lock.notifyAll();
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            } else if (counter % 2 == 1) {
                System.out.println(counter +" Written By Thread-"+ Thread.currentThread().getName());
                counter++;

                try {
                    lock.notifyAll();
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
  }
}

I have created a pretty basic Solution for it using the Reentrant Lock.

package com.multithreding.trylock;

import java.util.concurrent.locks.ReentrantLock;

public class TryLock extends Thread {

    static int intitialCount = 50;          //Value till which you want to print
    int valueToSubtract = 0;                //Value by which difference you want to print the series like 1,2,3
    static ReentrantLock alternate = new ReentrantLock();

    public TryLock(String name) {
        this.setName(name);
    }

    public void run() {
        while (intitialCount > 1) {         

            if (valueToSubtract > 0) {
                alternate.lock();
                intitialCount = intitialCount - valueToSubtract;
                valueToSubtract = 0;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("value Subtracted " + intitialCount + " by the Thread" + this.getName());
                alternate.unlock();
            } else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                valueToSubtract++;
            }
        }

    }

}

package com.multithreding.trylock;

public class AlternatePrint {

    public static void main(String[] args) throws InterruptedException{
        //You  can add as many thread to print then in different number of series
        TryLock t1 = new TryLock("Odd One");
        TryLock t2 = new TryLock("Even Value");
        t1.start();
        t2.start();

    }

}

This solution is modular as well,

  • You can add 'n' number of Threads to print the alternate series. ie Using 3 thread at once

  • You can also print the series with more than Difference of more than 1. ie 1,3,5 etc

package thread;

public class Pingpong extends Thread {
    static StringBuilder object = new StringBuilder("");
    static int i=1;

    @Override
    public void run() {
        working();
    }
    void working() {
        while (i<=10) {
            synchronized (object) {
                try {
                    System.out.println(Thread.currentThread().getName() +"  "+ i);
                    i++;
                    object.notify();
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Pingpong();
        Thread t2 = new Pingpong();
        t1.setName("Thread1");
        t2.setName("Thread2");
        t1.start();
        t2.start();
    }
}

Thread1  1
Thread2  2
Thread1  3
Thread2  4
Thread1  5
Thread2  6
Thread1  7
Thread2  8
Thread1  9
Thread2  10

This answer is generic ie not only to print numbers alternately from 2 threads but to execute 2 threads alternately. The above approaches are commendable but this one doesn't need any lock but instead it uses an AtomicInteger variable alongwith 2 AtomicBooleans to indicate when one thread has finished executing so that the other can finish executing the rest of its remaining execution.

This will work in all 3 cases:

  1. When number of executions of both threads are same.
  2. When first thread finishes before second thread and second thread has more number of executions than first thread.
  3. When second thread finishes before first thread and first thread has more number of executions than second thread.
public class TestAlternateExecutionOfTwoThreads
{
    private static final AtomicInteger count = new AtomicInteger(0);
    private static final AtomicBoolean firstIsDone = new AtomicBoolean(false);
    private static final AtomicBoolean secondIsDone = new AtomicBoolean(false);

    // change the below values to change the number of iterations each thread should 
    // run. In this example, the initial value are hard-coded but you can change 
    // them as well.
    private static final int finalOfFirstThread = 10;
    private static final int finalOfSecondThread = 109;

    public static void main(String[] args)
    {
        Runnable r1 = () -> {
            int i = 1;
            for(; i <= finalOfFirstThread; )
            {
                while(count.get() == 0)
                {
                    System.out.println(i);
                    count.incrementAndGet();
                    i++;
                }
                if(count.get() == 1 && secondIsDone.get() && i != (finalOfFirstThread + 1))
                {
                    System.out.println(i);
                    i++;
                }
            }
            firstIsDone.set(true);
        };

        Runnable r2 = () -> {
            int j = 100;
            for (; j <= finalOfSecondThread; )
            {
                while(count.get() == 1)
                {
                    System.out.println(j);
                    count.decrementAndGet();
                    j++;
                }
                if(count.get() == 0 && firstIsDone.get() && j != (finalOfSecondThread + 1))
                {
                    System.out.println(j);
                    j++;
                }
            }
            secondIsDone.set(true);
        };

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();

    }
}

This is another solution:

     Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            synchronized (lock) {
                for (int i = 1; i <= 50; i += 2) {
                    System.out.println("T1=" + i);

                    t1turn = false;
                        try {
                            lock.notifyAll();
                            lock.wait();
                        } catch (InterruptedException e) {
                        }
                }
            }

        }
    });
    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            synchronized (lock) {
                for (int i = 2; i <= 50; i += 2) {
                    if (t1turn)
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                        }
                    System.out.println("T2=" + i);
                    t1turn = true;
                    lock.notify();
                }
            }
        }
    });
    t1.start();
    t2.start();

I guess this might help. Although it is not standard but i hope it provides a simpler approach.

public class ThreadDemo
{
    public static void main (String [] args)
    {
        PrintDemo pd=new PrintDemo();     
        MyThread1 mt1 = new MyThread1 ("T1",pd);
        MyThread2 mt2 = new MyThread2 ("T2",pd);     
        mt1.start ();
        mt2.start();
    }
}
class PrintDemo {
    private boolean oddFlag=true;
    public synchronized void printOdd(int i,String tName){
        if(oddFlag==false){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
        }else{
            System.out.println("\nThread "+tName+" count:"+i);
            oddFlag=false;
            notify();
        }
    }
    public synchronized void printEven(int i,String tName){
        if(oddFlag==true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   
        }else{
            System.out.println("\nThread "+tName+" count:"+i);
            oddFlag=true;
            notify();
        }
    }   
}
class MyThread1 extends Thread
{
    private PrintDemo pd;
    private String name;

    MyThread1(String threadName,PrintDemo pd){
        this.name=threadName;
        this.pd=pd;
    }  
    public void run ()  
    {
       for(int i=1;i<=50;i+=2){
            pd.printOdd(i,name);
       }
    }
}
class MyThread2 extends Thread
{
    private PrintDemo pd;
    private String name;    
    MyThread2(String threadName,PrintDemo pd){
        this.name=threadName;
        this.pd=pd;
    }   
    public void run ()
    {
        for(int i=2;i<=50;i+=2){
            pd.printEven(i,name);                   
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM