2012-07-18 164 views
13

還有線程T1,T2T3,我們如何確保線程T2運行後T1和線程T3T2後運行?訪談:如何確保一個線程在另一個線程之後運行?

在我的採訪中詢問了這個問題。我沒有回答。請詳細解釋。

+4

答:退出試圖使用分開的線程來完成明顯的順序任務。線程的要點是能夠在概念上一次完成兩件事情。如果一個線程必須在另一個線程開始之前完成,那麼他們沒有業務是獨立的線程;使他們這樣,然後試圖強制他們的序列只會增加你的複雜性。 – cHao 2012-07-18 17:55:01

回答

1

線程也是可運行的。你可以簡單地依次運行它們:

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

這顯然沒什麼興趣。

假設他們想要的線程並行運行,一個解決辦法是讓每個線程開始下一個,因爲the JMM guarantees that

調用開始()上線之前發生的任何行動在開始的線程中。

+1

你是不是指'start()'他們? – Gray 2012-07-18 15:27:36

+0

@垃圾否:運行它們。 – assylias 2012-07-18 15:27:49

+6

然後他們不是「主題」。他們只是對象。我懷疑這是面試問題的一個很好的答案。 – Gray 2012-07-18 15:28:22

0

與創建它們的其他各胎面創建一個優先級隊列。 然後,您可以在完成後應用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() 

實現留作練習,所以下次你得到它的權利!

2

在每個線程(除T1)的開始,使之加入到通話(),它的前身。使用執行程序(而不是直接線程)是另一種選擇。人們也可以看看使用信號量--T1應該在完成時釋放許可證,T2應該嘗試獲得兩個許可證,並且在完成時釋放它們,T3應該嘗試獲得三個許可證&等等。使用加入或執行者將是首選路線。

15

這將是最簡單,最笨的辦法:

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

加油 - 你抱怨我依次運行我的runnables!你至少可以讓它們平行一些! – assylias 2012-07-18 15:42:11

+0

除非您將「T1在T2之後運行」解釋爲「T1在T2結束之後啓動」。 – assylias 2012-07-18 15:49:11

+3

@assylias這就是我對它的解釋。每個人都會同意,你的解決方案對於這個用例來說是一個真正的真實世界的勝利,但是這符合所述的要求。 – 2012-07-18 16:07:04

2

一種方式做到這一點會是像下面這樣。雖然這很複雜。您可能需要使用java.util.concurrent.CyclicBarrier類。

當它完成每個線程設置布爾值,並通知下一個線程繼續。儘管這是一個AtomicBoolean類,我們需要的​​所以我們可以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(); 
      } 
     } 
     ... 
    } 
} 
+1

我認爲在'T2'的run()方法中你試圖說'synchronized(lock2){'而不是'synchronized(lock3){' – 2013-08-26 18:50:54

+0

的確。謝謝@KuldeepJain。 – Gray 2013-08-29 14:56:00

+0

@Gray,在這種情況下使用'AtomicBoolean'而不是'Boolean'是否有優勢? – Learner 2013-09-11 09:14:28

3

最明顯的,也是最簡單的方法已經發表@Assylias - 有T1 run方法創建/啓動T2和T2運行方法創建/啓動T3。

是,恕我直言,近乎毫無意義,但它可以做。

解決方案使用JOIN()不回答這個問題 - 他們保證線程的終止是有序的,他們不運行。如果面試官不明白,那麼無論如何你都需要找到另一份工作。

在接受採訪時,我的回答是'For *爲什麼?線程通常用於避免你正在問的問題!'。

1

猜測面試官問的是三個線程按順序進行工作。例如,如果一個線程打印1,4,5 ...第2,5,8和三分之三3,6,9 etc ..輸出應該be 1,2,3,4,5 ..... Ist thread print 1 and give 2nd thread to print 2..etc。,

我試過使用cyclebarriers。只要'one'打印1IT給人機會,兩成調用cb.wait,當兩個運行它會依次調用三個類似的方式,它會continue.Let我知道,如果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(); 
    } 
} 
+0

今天在接受採訪時,我問到了完全相同的問題。無法回答。我正在尋找這個問題的答案,最終落在你的回答裏。它工作完美。 – siddhartha 2017-12-16 17:20:28

0

使用在啓動t之前,thread isAlive方法他線程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(); 
} 
1

我在一個更簡單的方法..嘗試使用等待和通知。(在我的上一個職位相對於循環障礙的方法)。

它使用'狀態'類......它有三種狀態: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(); 

     } 
    } 
0

同時使用,你可以運行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; 
    } 
} 
0
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; 
} 

} 
0

併發封裝具有更好的類使用共享對象。 其中一種方式就是這樣。

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

我認爲這可以幫助你。

0

通過使用連接可以確保一個接一個地運行一個線程。

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

} 
+0

請格式化代碼並添加一些解釋。 – Sid 2017-02-10 06:17:46

0

我們如何能夠確保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 條件1在它的run方法,這將是由T1信號等待(從T1的run方法,T1開始後/完成其任務)。

同樣具有T3 等待條件2在它的運行方法,該方法將是通過T2信號通知(從T2的運行方法中,在啓動後/完成它的任務)。

0

有線程T1,T2和T3,我們如何確保線程T2在T1之後運行 並且線程T3在T2之後運行? 或 有三個線程T1,T2和T3?你如何確保Java中的序列T1,T2,T3? 問題主要是T3應該先完成,T2秒和T1完成。 我們可以使用使用線程類的join()方法。 爲確保執行三個線程,您需要先開始最後一個線程,例如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(); 


    } 
} 

從輸出結果可以看出,線程開始順序不同,因爲您不知道哪個線程將獲得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(); 
    } 
} 
} 

輸出是: 抽動 抽動 TAC TAC 腳趾 腳趾

相關問題