访谈:如何确保一个接一个的线程运行?

有线程T1T2T3 ,我们怎样才能确保线程T2T1之后运行而线程T3T2之后运行?

我的采访中提到了这个问题。 我没回答。 请详细解释。

这将是最简单,最愚蠢的方法:

 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(); 

@Assylias已经发布了明显且最简单的方法 – 有T1运行方法创建/启动T2和T2运行方法创建/启动T3。

恕我直言,这是毫无意义的,但它可以做到。

使用Join()的解决方案不回答问题 – 它们确保线程的终止是有序的,而不是它们的运行。 如果面试官没有得到,那么无论如何你都需要找到另一份工作。

在一次采访中,我的答案是’为了清酒为什么? 线程通常用于避免你所要求的!’。

一种方法是这样的。 虽然这很复杂。 您可能希望使用java.util.concurrent.CyclicBarrier类。

每个线程完成后设置布尔值并通知下一个线程继续。 即使它是一个AtomicBoolean类,我们也需要synchronized所以我们可以对它进行wait()notify()

传入锁定对象或者在T2T3上有一个begin()方法会更清晰,这样我们就可以隐藏这些对象内部的锁。

 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(); } } ... } } 

在每个线程的开头(t1除外),让它在它的前身上调用join()。 使用执行程序(而不是直接使用线程)是另一种选择。 人们还可以看一下使用信号量–T1应该在完成时释放许可证,T2应该尝试获得两个许可证,并在完成后释放它们,T3应该尝试获得三个许可证等等。 使用连接或执行器将是首选路由。

线程也是可运行的。 您可以按顺序运行它们:

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

这显然没什么兴趣。

假设他们希望线程并行运行,一个解决方案是让每个线程启动下一个线程,因为JMM保证 :

在启动线程中的任何操作之前发生对线程的start()调用。

我尝试了一种更简单的方式..使用等待并通知。(与我的上篇文章中的循环屏障方法相反)。

它使用’State’类……它有三种状态:1,2,3。(默认为3)。 当它为3时,它触发t1,1触发t2,2触发t3,依此类推。

类:状态// int i = 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(); } } 

猜猜面试官要问的是三个线程按顺序完成工作。例如,如果一个线程打印1,4,5 …第二个2,5,8和三个3,6,9等。输出应为1,2 ,3,4,5 ….. Ist线程打印1并有机会第二个线程打印2..etc。,

我尝试使用cyclebarriers。只要’one’打印1it就有机会两个,因为它调用cb.wait,当两个运行时它将以类似的方式调用三个它将继续。让我知道如果thr是任何错误在代码中

 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(); } } 

创建一个优先级队列,其中每个胎面都在其中创建。 然后,您可以在完成后应用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() 

实施留作练习,所以下次你做对了!

在启动线程T2和T3之前使用线程isAlive方法。

 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(); } 

在使用时尝试使用以下代码,您可以以这种方式运行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 runnables = new HashSet(); 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; } } 

并发包具有更好的类来使用共享对象。 其中一种方式是这样的。

 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; } 
 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; } } 
 import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; class Worker implements Runnable { BlockingQueue 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); } } 

我想这可以帮到你。

通过使用join,您可以确保一个接一个地运行线程。

 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"); } } 

我们怎样才能确保线程T2在T1之后运行而线程T3在T2之后运行?

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

我们可以使用条件接口。

我们需要两个条件绑定到一个Lock : condition1来协调T1和T2, condition2来协调T2和T3。
条件1传递给T1和T2, 条件2传递给T2和T3。

因此,我们将在其运行方法中对条件1进行T2 等待 ,该方法将由T1(从T1的运行方法,在T1启动/完成其任务之后) 发出信号

类似地,在它的run方法中有一个T3 await on condition2 ,它将由T2(来自T2的run方法,在它启动/完成它的任务之后) 发出信号

有线程T1,T2和T3,我们怎样才能确保线程T2在T1之后运行而线程T3在T2之后运行? 或者有三个线程T1,T2和T3? 你如何确保Java中的序列T1,T2,T3? 问题基本上是T3应该先完成,T2秒和T1最后。 我们可以使用线程类的join()方法。 为了确保执行三个线程,您需要首先启动最后一个线程,例如T3,然后以相反的顺序调用join方法,例如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(); } } 

从输出中,您可以看到线程以不同的顺序启动,因为您不知道哪个线程将获得CPU。 它是Thread Scheduler的决定,因此我们无能为力。 但是,您可以看到线程以正确的顺序完成,即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(); } } } 

输出是:tic tic tac tac toe toe