Pregunta

How will you execute Three threads sequentially? For eg. Thread1, Thread2, Thread3. It is not possible to pass the reference of one Thread to the other and invoke from the run() method.

So code should be like this:

 Thread1.start();
 Thread2.start();
 Thread3.start();

and out put should be

 Printing Thread1
 Printing Thread2
 Printing Thread3

This can be possible by using ThreadPoolExecutor and using a blocking queue but even that is not an acceptable answer.

¿Fue útil?

Solución

Use ExecutorService in java.util.concurrent package. More precisely use Executors.newSingleThreadExecutor();

Otros consejos

You could use Executors.newSingleThreadExecutor(), but strictly speaking this launches only one Thread, so may not be expected solution.

The simpliest solution using just Thread class:

Thread1.start();
Thread1.join();
Thread2.start();
Thread2.join();
Thread3.start();
Thread3.join();

(I omitted exception handling for clarity, Thread.join() can throw InterruptedException)

The simplest answer is

Thread1.run();
Thread2.run();
Thread3.run();

The problem with unrealistic questions is they often have an uninformative answer. ;)

The whole point of having threads is to run them concurrently. If you are not doing that at all, don't use threads.

You might say that; you cannot call the run() method, in which case you cannot use ThreadPoolExecutor because it calls the run() method for you. i.e. thats what submit() eventually does.

EDIT: The results are completely deterministic, becaus ethe fact that there is a Thread involved is irrelivent.

static class PrintThread extends Thread {
    public PrintThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++)
            System.out.println(getName() + ": " + i);
    }
}

public static void main(String args[]) {
    Thread thread1 = new PrintThread("A");
    Thread thread2 = new PrintThread("B");
    Thread thread3 = new PrintThread("C");

    thread1.run();
    thread2.run();
    thread3.run();
}

Prints

A: 0
A: 1
.. deleted ..
C: 98
C: 99

as expected.

Since this is an interview question, they're looking for specific knowledge, not a "well it's obviously better to do it this way" answer. It also seems that they'll likely strike out solution after solution until they get the answer they want.

Odds are they want to see if you can implement inter-thread communications yourself. But they don't want you to do it the easy way (thread references available). Otherwise, you could just do thread.join().

So have all three threads grab some bit of shared memory (synchronized static class). Have each thread check a public static int nextThread(). Upon successful comparison that they are the next thread, they should do their work and update public static setNextThread(int value) with the value of the next thread to be processed.

The key is to do this in a thread-safe manner; however, if you can guarantee unique thread identifiers and ensure that no two threads have the same identifier, you can (with careful coding) even manage to do this without synchronization.

If it were not related to various ways of invoking these threads, theoretically, they should use acquire a common sempahore, and release it when done printing.
JDK has an inbuilt semaphore.

Threads can be executed sequentially by using ExecutorService. Find below example.

public class SeqThread {

    public static void main(String[] arg) {
          new SeqThread().execute();
    }

    public void execute() {
        try {
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(R);
        executor.submit(R2);
        executor.shutdown();

            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    Runnable R = new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            for(int i=0;i<10;i++)
            {
                System.out.println("In Thread One "+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };

    Runnable R2 = new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            for(int i=0;i<10;i++)
            {
                System.out.println("In Thread Two="+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    };
}

Forcing threads to run in ordered manner is like killing the very concept of multithreading, its more like single threaded program' sub-routine execution. As its interview question so everything is OK. Here is the program that test the logic not with 4 but 50 threads-

public class Outer {
    private Thread[] jobs;
    private String[] names;
    private int indx;

public Outer(int numOfThreads) {
    jobs = new Thread[numOfThreads];
    names = new String[numOfThreads];
    indx = numOfThreads - 1;
}

class Inner implements Runnable {
public void run() {
    while (true) {
       if (names[indx].equals(Thread.currentThread().getName())) {
          indx--;
          break;
       }
       else {
          try { Thread.sleep(20); } catch(InterruptedException ie) {}
       }
    }
    // now current thread will join behind the previous one..
    if (indx >= 0) try { jobs[indx].join(); } catch(InterruptedException ie) {}

    /***** YOUR ACTUAL CODE GOES FROM HERE *****/

    // at last check is it working ?
    System.out.println(Thread.currentThread().getName());
  }
}

public void f() {
    Inner target = new Inner();
    // initializing all threads..
    for (int i = 0; i < jobs.length; jobs[i++] = new Thread(target));
    for (int i = 0; i < names.length; names[i] = jobs[i++].getName());

    // checking name of threads..
    for (int i = 0; i < names.length; System.out.println(names[i++]));

    System.out.println();

    // now we start all threads..
    for (int i = 0; i < jobs.length; jobs[i++].start());
  }

public static void main(String[] args) {
    new Outer(50).f();               // testing logic not with 4 but 50 threads..
  }
}

You can find everything there: http://download.oracle.com/javase/tutorial/essential/concurrency/index.html

Especially read about notifications and synchronization between threads.

P.S. And remember, even if you pass the interview you'll still had to work! :)

(Ok, I'll give some hints: look the description of such methods as Object.wait() and Object.notifyAll() it is the simpliest but also very usefull mechanism)

newSingleThreadExecutor. A single-threaded executor creates a single worker thread to process tasks, replacing it if it dies unexpectedly. Tasks are guaranteed to be processed sequentially according to the order imposed by the task queue (FIFO, LIFO, priority order).

This could be a trick question. Maybe they don't want to hear the solution to this specific problem but want you to back track to the source of the problem and come up with a better solution.

I've used basic thread communication model and it could be more simplified as well. Let's say you have 3 threads, one is printing 0, second one is printing odd number and third one is printing even number liker this 01 02 03 04 05....

public class app{
        int status=0;
        public static void main(String[] args) throws InterruptedException{

            app obj = new app();
            Thread t1 = new Thread(new print(obj,0));
            Thread t2 = new Thread(new print(obj,1));
            Thread t3 = new Thread(new print(obj,2));
                t1.start();t2.start();t3.start();
            }

    }
    class print implements Runnable{
        app obj;
        int a;
        public print(app obj, int a) {
            this.obj=obj;
            this.a=a;
        }
        @Override
        public void run() {
            try{

                if(a==0){
                    synchronized(obj){
                    for (int i = 0; i < 21; i++) {
                        while(obj.status!=0 && obj.status!=3){
                            obj.wait();
                            } 

                        System.out.print(0);
                        if(obj.status==0)//even sets status to 0 so next one is odd
                            obj.status=1;
                        else//odd sets status to 3 so next one is even
                            obj.status=2;
                        obj.notifyAll();
                        }
                    }
                }
                    else if(a%2!=0){
                        synchronized (obj) {
                            for (int i = 0; i < 11; i++) {
                                while(obj.status!=1){
                                    obj.wait();
                                    } 

                                System.out.print(a);
                                a+=2;
                                obj.status=3;
                       //3 decides 0 came after odd, so next one           
                      //after zero is even
                                obj.notifyAll();
                            }
                        }
                    }
                    else{
                        synchronized (obj) {
                            for (int i = 0; i < 11; i++) {
                                while(obj.status!=2){
                                    obj.wait();
                                    } 

                                System.out.print(a);
                                a+=2;
                                obj.status=0;
                                obj.notifyAll();
                            }
                        }
                    }
                }




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

I am not sure if I understood the question completely but this seems like a situation where we want to print the threads in sequence. One example is to print the value using threads in a sequence like:

Thread - 0 output: 1

Thread - 1 output: 2

Thread - 2 output: 3

Thread - 0 output: 4

Thread - 1 output: 5

Thread - 2 output: 6 and so on..

If this is the requirement then a generic solution for n threads can be written where each thread will wait for its turn (using common object on which it will try to acquire lock).

class ResourceLock {
    private volatile int currentThreadId;
    private final int totalThreads;

    public ResourceLock(int threadsCount) {
        this.currentThreadId = 0;
        this.totalThreads = threadsCount;
    }
    public void assignTokenToNextThread(int currentThreadNum) {
        this.currentThreadId = (currentThreadNum + 1) % totalThreads;
    }
    public int getCurrentThreadId() {
        return currentThreadId;
    }
}

Now a worker thread will do its job and use the instance of above class for locking purpose:

class Worker extends Thread {
    private final ResourceLock resourceLock;
    private final int threadId;                     // id of this thread
    private final AtomicInteger counter;            // counter shared by all threads, will print number in sequence.
    private volatile boolean running = true;        // flag to stop this thread when necessary
    public Worker(ResourceLock resourceLock, int threadNumber, AtomicInteger counter) {
        this.resourceLock = resourceLock;
        this.threadId = threadNumber;
        this.counter = counter;
    }
    @Override
    public void run() {
        while (running) {
            try {
                synchronized (resourceLock) {
                    while (resourceLock.getCurrentThreadId() != this.threadId) {
                        resourceLock.wait();
                    }
                    System.out.println("Thread:" + threadId + " value: " + counter.incrementAndGet());
                    Thread.sleep(1000);
                    resourceLock.assignTokenToNextThread(this.threadId);
                    resourceLock.notifyAll();
                }
            } catch (Exception e) {
                System.out.println("Exception: " + e);
            }
        }
    }
    public void shutdown() {
        running = false;
    }
}

And this can be tested as:

public static void main(String[] args) throws InterruptedException {
        final int threadsCount = 3;
        final ResourceLock lock = new ResourceLock(threadsCount);
        Worker[] threads = new Worker[threadsCount];
        final AtomicInteger counter = new AtomicInteger(0);
        for(int i=0; i<threadsCount; i++) {
            threads[i] = new Worker(lock, i, counter);
            threads[i].start();
        }
        Thread.sleep(20000);
        System.out.println("Will try to shutdown now...");
        for(Worker worker: threads) {
            worker.shutdown();
        }
    }
public static void main(String[] args)throws InterruptedException {

    MyRunnable r = new MyRunnable();
    Thread t1 = new Thread(r,"A");
    Thread t2 = new Thread(r,"B");
    Thread t3 = new Thread(r,"C");
    t1.start();
    Thread.sleep(1000);
    t2.start();
    Thread.sleep(1000);
    t3.start();



}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top