Подтвердить что ты не робот

Интервью: Как обеспечить, чтобы поток работал за другим?

Есть поток T1, T2 и T3, как мы можем гарантировать, что поток T2 запускается после T1 и потока T3 после T2?

Этот вопрос задавали в моем интервью. Я не ответил. Пожалуйста, объясните подробно.

4b9b3361

Ответ 1

Это будет самый простой, самый тупой подход:

final Thread t1 = new Thread(new T1()); // assume T1 is a Runnable
t1.start();
t1.join();
final Thread t2 = new Thread(new T2());
t2.start();
t2.join();
final Thread t3 = new Thread(new T3());
t3.start();
t3.join();

Ответ 2

Очевидный и самый простой способ уже был отправлен @Assylias - есть метод запуска T1 create/start T2 и T2 запустить метод create/start T3.

Это, ИМХО, граничит с бессмысленным, но это можно сделать.

Решения, использующие Join(), не отвечают на вопрос - они гарантируют, что прекращение потоков упорядочено, а не их запуск. Если собеседник не понимает этого, вам все равно нужно найти другую работу.

В интервью, мой ответ будет "Для * ради чего? Темы используются обычно, чтобы избежать того, что вы просите!".

Ответ 3

В начале каждого потока (кроме t1) заставьте его вызвать join() на нем предшественника. Использование исполнителей (вместо прямых потоков) - это еще один вариант. Можно также взглянуть на использование семафоров - T1 должен освободить разрешение после завершения, T2 должен попытаться получить два разрешения и отпустить их, когда это будет сделано, T3 должен попытаться получить три разрешения и так далее. Использование соединения или исполнителей было бы предпочтительным маршрутом.

Ответ 4

Один из способов сделать это - это что-то вроде следующего. Это сложно. Для этого вы можете использовать класс java.util.concurrent.CyclicBarrier.

Каждый поток, когда он заканчивается, устанавливает логическое значение и уведомляет следующий поток для продолжения. Даже если это класс AtomicBoolean, нам нужен synchronized, поэтому мы можем wait() и notify() на нем.

Было бы проще проходить объекты блокировки или, возможно, иметь метод begin() на T2 и T3, чтобы мы могли скрыть блокировки внутри этих объектов.

final Object lock2 = new Object();
final Object lock3 = new Object();
boolean ready2;
boolean ready3;
...
public T1 implements Runnable {
    public void run() {
        ...
        synchronized (lock2) {
            // notify the T2 class that it should start
            ready2 = true;
            lock2.notify();
        }
    }
}
...

public T2 implements Runnable {
    public void run() {
        // the while loop takes care of errant signals
        synchronized (lock2) {
            while (!ready2) {
                lock2.wait();
            }
        }
        ...
        // notify the T3 class that it should start
        synchronized (lock3) {
            ready3 = true;
            lock3.notify();
        }
    }
}
...
public T3 implements Runnable {
    public void run() {
        // the while loop takes care of errant signals
        synchronized (lock3) {
            while (!ready3) {
                lock3.wait();
            }
        }
        ...
    }
}

Ответ 5

Потоки также являются runnables. Вы можете просто запустить их последовательно:

t1.run();
t2.run();
t3.run();

Это явно не представляет интереса.

Предполагая, что они хотят, чтобы потоки выполнялись параллельно, одно решение заключалось бы в том, чтобы каждый поток запускал следующий, поскольку JMM гарантирует, что

Выполняется вызов start() в потоке - перед любыми действиями в запущенном потоке.

Ответ 6

Угадайте, что вопрос интервьюера состоял из трех потоков, которые работают в последовательности. Например, если один поток печатает 1,4,5... второй 2,5,8 и третья 3,6,9 и т.д., вывод должен быть 1,2,3,4,5..... Ist thread prints 1 и дает возможность второму потоку печатать 2..etc.,

Я попробовал это с помощью циклических барьеров. Как только "один" печатает 1, дает шанс двум, так как он вызывает cb.wait, когда два прогона он в свою очередь вызовет три аналогичным образом, и он продолжит. Позвольте мне знать, если тр любые ошибки в коде

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class one implements Runnable{
    CyclicBarrier cb;
    one(CyclicBarrier cb){this.cb=cb;}
    public void run(){
        int i=1;
        while(true)
        {
            System.out.println(i);
            try {
                Thread.sleep(1000);
                cb.await();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            i=i+3;
        }
    }

}
class two implements Runnable{
    CyclicBarrier cb;
    int i=2;
    two(CyclicBarrier cb){this.cb=cb;}
    public void run(){


        System.out.println(i);
        try {
            cb.await();
            i=i+3;
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}


public class oneTwoThree {
    public static void main(String args[]){
        Runnable threePrinter = new Runnable() {
            int i=3;
            public void run() {
                System.out.println(i);
                i=i+3;
            }
        };


        CyclicBarrier bar2 =new CyclicBarrier(1,threePrinter);//, barrier1Action);
        two twoPrinter  =new two(bar2);
        CyclicBarrier bar1 =new CyclicBarrier(1,twoPrinter);

        Thread onePrinter=new Thread(new one(bar1));
        onePrinter.start();
    }
}

Ответ 7

Я попробовал гораздо проще... используя ожидания и уведомления (в отличие от подхода с циклическим барьером в моем предыдущем сообщении).

Он использует класс 'State', который получает три состояния: 1,2,3. (по умолчанию 3).  Когда он равен 3, он запускает t1, при 1 срабатывает t2, а в 2 - t3 и т.д.

Классы: Состояние //int я = 3 T1//печатает 1,4,7... T2//Печать 2,5,8 T3//Печать 3,6,9 и т.д.,

Пожалуйста, дайте мне знать ваши мнения или любые проблемы в коде. Спасибо.

Вот код.:

public class State {

    private int state ;

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

    public synchronized int getState() {
        return state;
    }

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


}


public class T1 implements Runnable {

    State s;
    public T1(State s) {
        this.s =s;
    }

    @Override
    public void run() {
        int i =1;

        while(i<50)
        {
            //System.out.println("s in t1 "+ s.getState());

            while(s.getState() != 3)
            {

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

                }

            }

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

                if(s.getState()==3)
                System.out.println("t1 "+i);
                s.setState(1);
                i = i +3 ;
                s.notifyAll();


            }

        }

    }

}




public class T2 implements Runnable {

    State s;
    public T2(State s) {
        this.s =s;
    }

    @Override
    public synchronized void run() {
        int i =2;

        while(i<50)
        {

            while(s.getState() != 1)
            {

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

                }

            }

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

                if(s.getState()==1)
                System.out.println("t2 "+i);
                s.setState(2);
                i = i +3 ;
                s.notifyAll();

            }

        }




    }


}



public class T3 implements Runnable {

    State s;
    public T3(State s) {
        this.s =s;
    }

    @Override
    public synchronized void run() {
        int i =3;

        while(i<50)
        {

            while(s.getState() != 2)
            {
                synchronized(s)
                {
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }

            }

            synchronized(s)
            {

                if(s.getState()==2)
                System.out.println("t3 "+i);
                i = i +3 ;
                s.setState(3);
                s.notifyAll();
            }

        }



    }}





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

            State s = new State();
            Thread t1 = new Thread(new T1(s));
            Thread t2 = new Thread(new T2(s));
            Thread t3 = new Thread(new T3(s));

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

        }
    }

Ответ 8

Создайте очередь приоритетов с каждым протектором в другом, который они создали. Затем вы можете применить Thread.join после завершения, удалить этот поток из очереди приоритетов, а затем снова выполнить первый элемент очереди. Псевдокод:

   pthread [3] my_threads
    my_queue
    for t in pthreads:
         my_queue.queue(t)

   while !my_queue.empty()
      pop the head of the queue
      wait until it complets
      thread.join()

реализация остается как упражнение, поэтому в следующий раз вы получите это правильно!

Ответ 9

Используйте метод threadAlive перед запуском потока T2 и T3.

Thread t1 = new Thread(new T1()); 
Thread t2 = new Thread(new T2()); 
Thread t3 = new Thread(new T3()); 
t1.start();

if(t1.isAlive()){   

    t2.start();

}

if(t2.isAlive()){

    t3.start();
}

Ответ 10

Попробуйте использовать приведенный ниже код, используя при этом n количество потоков таким образом.

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicExecutionOfThreads {

    public static void main(String args[]) {

        int totalNumOfThreads = 10;
        PrintJob printJob = new PrintJob(totalNumOfThreads);

        /*
        MyRunnable runnable = new MyRunnable(printJob, 1);
        Thread t1 = new Thread(runnable);

        MyRunnable runnable2 = new MyRunnable(printJob, 2);
        Thread t2 = new Thread(runnable2);

        MyRunnable runnable3 = new MyRunnable(printJob, 3);
        Thread t3 = new Thread(runnable3);

        t1.start();
        t2.start();
        t3.start();
        */

        //OR

        ExecutorService executorService = Executors
                .newFixedThreadPool(totalNumOfThreads);
        Set<Runnable> runnables = new HashSet<Runnable>();

        for (int i = 1; i <= totalNumOfThreads; i++) {
            MyRunnable command = new MyRunnable(printJob, i);
            runnables.add(command);
            executorService.execute(command);
        }

        executorService.shutdown();

    }
}

class MyRunnable implements Runnable {

    PrintJob printJob;
    int threadNum;

    public MyRunnable(PrintJob job, int threadNum) {
        this.printJob = job;
        this.threadNum = threadNum;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (printJob) {
                if (threadNum == printJob.counter) {
                    printJob.printStuff();

                    if (printJob.counter != printJob.totalNumOfThreads) {
                        printJob.counter++;
                    } else {

                        System.out.println();
                        // reset the counter
                        printJob.resetCounter();

                    }

                    printJob.notifyAll();

                } else {
                    try {
                        printJob.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

}

class PrintJob {
    int counter = 1;
    int totalNumOfThreads;

    PrintJob(int totalNumOfThreads) {
        this.totalNumOfThreads = totalNumOfThreads;
    }

    public void printStuff() {
        System.out.println("Thread " + Thread.currentThread().getName()
                + " is printing");

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public void resetCounter() {
        this.counter = 1;
    }
}

Ответ 11

package thread;

class SyncPrinter {
    public static void main(String[] args) {
        SyncPrinterAction printAction1 = new SyncPrinterAction(new int[]{1,5,9,13}, true);
        SyncPrinterAction printAction2 = new SyncPrinterAction(new int[]{2,6,10,14}, true);
        SyncPrinterAction printAction3 = new SyncPrinterAction(new int[]{3,7,11,15}, true);
        SyncPrinterAction printAction4 = new SyncPrinterAction(new int[]{4,8,12,16}, false);

    printAction1.setDependentAction(printAction4);
    printAction2.setDependentAction(printAction1);
    printAction3.setDependentAction(printAction2);
    printAction4.setDependentAction(printAction3);

    new Thread(printAction1, "T1").start();;        
    new Thread(printAction2, "T2").start();
    new Thread(printAction3, "T3").start();     
    new Thread(printAction4, "T4").start();



}
}

class SyncPrinterAction implements Runnable {

private volatile boolean dependent;
private SyncPrinterAction dependentAction;
int[] data;

public void setDependentAction(SyncPrinterAction dependentAction){
    this.dependentAction = dependentAction;

}

public SyncPrinterAction( int[] data, boolean dependent) {
    this.data = data;
    this.dependent = dependent;
}

public SyncPrinterAction( int[] data, SyncPrinterAction dependentAction, boolean dependent) {
    this.dependentAction = dependentAction;
    this.data = data;
    this.dependent = dependent;
}

@Override
public void run() {
    synchronized (this) {

        for (int value : data) {

            try {
                while(dependentAction.isDependent())
                    //System.out.println("\t\t"+Thread.currentThread().getName() + " :: Waithing for dependent action to complete");
                wait(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            dependentAction.setDependent(true);

            System.out.println(Thread.currentThread().getName() + " :: " +value);
            dependent = false;
        }

    }

}

private void setDependent(boolean dependent) {
    this.dependent = dependent;

}

private boolean isDependent() {
    return dependent;
}

}

Ответ 12

Параллельный пакет имеет лучшие классы для использования общего объекта. Один из способов такой.

public static void main(String[] args) {

    final Lock lock = new ReentrantLock();
    final Condition condition = lock.newCondition();

    ThreadId threadId = new RunInSequence.ThreadId();
    threadId.setId(1);
    Thread t1 = setThread("thread1",lock, condition, 1, 2, threadId);
    Thread t2 = setThread("thread2",lock, condition, 2, 3, threadId);
    Thread t3 = setThread("thread3",lock, condition, 3, 1, threadId);
    t1.start();
    t2.start();
    t3.start();

}

private static class ThreadId {
    private int id;

    public ThreadId() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

private static Thread setThread(final String name,final Lock lock, final Condition condition, int actualThreadId, int nextThreadId,
        ThreadId threadId) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (threadId.getId() != actualThreadId) {
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(name+"prints: " + actualThreadId);
                    threadId.setId(nextThreadId);
                    condition.signalAll();
                } finally {
                    lock.unlock();
                }
            }
        }
    };
    return thread;
}

Ответ 13

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class Worker implements Runnable {

  BlockingQueue<Integer> q = new LinkedBlockingQueue<>();
  Worker next = null; // next worker in the chain

  public void setNext(Worker t) {
    this.next = t;
  }

  public void accept(int i) {
    q.add(i);
  }

  @Override
  public void run() {
    while (true) {
      int i;
      try {
        i = q.take(); // this blocks the queue to fill-up
        System.out.println(Thread.currentThread().getName() + i);
        if (next != null) {
          next.accept(i + 1); // Pass the next number to the next worker
        }
        Thread.sleep(500); // Just sleep to notice the printing.
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

public class PrintNumbersSequentially {
  public static void main(String[] as) {

    Worker w1 = new Worker();
    Worker w2 = new Worker();
    Worker w3 = new Worker();

    w1.setNext(w2);
    w2.setNext(w3);
    w3.setNext(w1);

    new Thread(w1, "Thread-1: ").start();
    new Thread(w2, "Thread-2: ").start();
    new Thread(w3, "Thread-3: ").start();

    //Till here all the threads have started, but no action takes place as the queue is not filled for any worker. So Just filling up one worker.
    w1.accept(100);
  }
}

Я думаю, это может помочь вам.

Ответ 14

Используя соединение, вы можете обеспечить выполнение потока один за другим.

class MyTestThread implements Runnable{

    public void run() {
    System.out.println("==MyTestThread : START : "+Thread.currentThread().getName());
    for(int i = 0; i < 10; i++){
        System.out.println(Thread.currentThread().getName() + " :i = "+i);
    }
    System.out.println("==MyTestThread : END : "+Thread.currentThread().getName());
    }

}
public class ThreadJoinTest {

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new MyTestThread(), "t1");
        Thread thread2 = new Thread(new MyTestThread(), "t2");

        thread1.start();
        thread1.join();
        thread2.start();
        thread2.join();

        System.out.println("====All threads execution===completed");
    }

}

Ответ 15

как мы можем гарантировать, что поток T2 запускается после того, как T1 и поток T3 запускаются после T2?

NOTE: Assuming that it is not about scheduling the threads in the required order 

Мы могли бы использовать Condition интерфейс.

Нам потребуются два условия, связанные с одним Lock: условие1 для координации T1 и T2, условие2 для координации T2 и T3.
Передать условие1 в T1 и T2, условие2 в T2 и T3.

Таким образом, мы ожидаем, что T2 будет ждать condition1 в этом методе run, который будет сигнализироваться T1 (из метода запуска T1, после того, как T1 начнет/завершит свою задачу). T3 ждет в condition2 в этом методе запуска, который будет сигнализироваться T2 (из метода запуска T2 после запуска/завершения задачи).

Ответ 16

Существуют потоки T1, T2 и T3, как мы можем гарантировать, что поток T2 запускается после того, как T1 и поток T3 запускаются после T2? ИЛИ Есть три потока T1, T2 и T3? Как вы обеспечиваете последовательность T1, T2, T3 в Java? Вопрос в основном заключается в том, что T3 должен закончить сначала, второй T2 и T1. Мы можем использовать метод join() класса thread. Чтобы обеспечить выполнение трех потоков, вам нужно сначала запустить последний, например, T3, а затем вызвать методы соединения в обратном порядке, например. T3 вызывает T2.join,  и T2 вызывает T1.join. Таким образом, T1 закончит сначала, а T3 завершит последний.

public class Test1 {
    public static void main(String[] args) {
        final Thread t1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("start 1");
                System.out.println("end 1");
            }//run
        });

        final Thread t2  = new Thread(new Runnable() {
            public void run() {
                System.out.println(" start 2 ");
                try {
                    t1.join(2000);
                } catch (Exception e) {
                    e.getStackTrace();
                }
                System.out.println(" end 2");
            }
        }) ;

        final Thread t3 = new Thread( new Runnable() {
            public void run() {
                System.out.println(" start 3 ");

                try {
                    t2.join(4000);
                }catch(Exception e) {
                    e.getStackTrace();
                }
                System.out.println(" end  3 ");
            }
        });
       // we are reversing the order of the start() method
        t3.start();
        t2.start();
        t1.start();


    }
}

Из вывода вы увидите, что потоки запущены в другом порядке, так как вы не знаете, какой поток получит процессор. Это решение Планировщика потоков, поэтому мы ничего не можем сделать. Но вы можете видеть, что потоки закончены в правильном порядке, т.е. T1, затем T2, а затем T3.

Есть и другой способ сделать это. Псевдокод:

t1.start();

    t1.join(); // signals t2 to wait

    if( !t1.isAlive()) {
        t2.start();// if t1 is finished then t2 will start
    }

    t2.join();//signals t3 to wait

    if (!t2.isAlive()) {
        t3.start(); 
    }

Возьмем полную программу:

 public class Tic implements Runnable{
   public void run() {
       try {
            for (int i = 0; i < 2; i++) {
                  System.out.println("tic");
            }
    } catch (Exception e) {
        // TODO: handle exception
        e.getStackTrace();
    }
   }
}

public class Tac implements Runnable{
       public void run() {
           try {
                for (int i = 0; i < 2; i++) {
                      System.out.println("tac");
                }
        } catch (Exception e) {
            // TODO: handle exception
            e.getStackTrace();
        }
       }
    }
public class Toe implements Runnable{
       public  void run() {
           try {
                for (int i = 0; i < 2; i++) {
                      System.out.println("toe");
                }
        } catch (Exception e) {
            // TODO: handle exception
            e.getStackTrace();
        }
       }
    }

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

        Tic tic = new Tic();
        Tac tac = new Tac();
        Toe toe = new Toe();
        Thread t1 = new Thread(tic);
        Thread t2 = new Thread(tac);
        Thread t3 = new Thread(toe);
        t1.start();

        t1.join(); // signals t2 to wait

        if( !t1.isAlive()) {
            t2.start();// if t1 is finished then t2 will start
        }

        t2.join();//signals t3 to wait

        if (!t2.isAlive()) {
            t3.start(); 
        }

    }catch(InterruptedException e) {
        e.printStackTrace();
    }
}
}

Выход: тик тик нолики нолики палец схождение