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

时间:2012-07-18 15:25:27

标签: java multithreading

有线程T1T2T3,我们如何确保线程T2T1和线程T3之后运行在T2之后?

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

17 个答案:

答案 0 :(得分:21)

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

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

答案 1 :(得分:4)

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

恕我直言,这一点毫无意义,但可以做到。

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

在接受采访时,我的答案是'为了 * 为什么?线程通常用来避免你所要求的!'。

答案 2 :(得分:3)

这样做的一种方法如下。虽然这很复杂。您可能希望使用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();
            }
        }
        ...
    }
}

答案 3 :(得分:2)

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

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

这显然没什么兴趣。

假设他们希望线程并行运行,一个解决方案就是让每个线程开始下一个线程,因为the JMM guarantees that

  

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

答案 4 :(得分:2)

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

答案 5 :(得分:1)

猜猜是什么面试官要求三个线程按顺序完成工作。例如,如果一个线程打印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();
    }
}

答案 6 :(得分:1)

有线程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 脚趾 趾

答案 7 :(得分:1)

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

它使用了一个&#39;州&#39; class ...获得三种状态: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();

        }
    }

答案 8 :(得分:0)

package io.hariom.threading;

//你有三个线程T1、T2和T3,你如何保证它们按T1、T2、T3的顺序完成?

公共类ThreadTest1 {

public static void main(String[] args) {

    Thread thread1 = new Thread(new MyRunnable(null));
    Thread thread2 = new Thread(new MyRunnable(thread1));
    Thread thread3 = new Thread(new MyRunnable(thread2));
    thread1.start();
    thread2.start();
    thread3.start();

}

}

class MyRunnable 实现 Runnable { 线程t;

MyRunnable(Thread t) {
    this.t = t;

}

@Override
public void run() {
    if (t != null) {
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(Thread.currentThread().getName() + " starts");
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(Thread.currentThread().getName() + " ends");
}

}

答案 9 :(得分:0)

  

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

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

我们可以使用Condition界面。

我们需要两个条件绑定到一个Lock condition1 来协调T1和T2, condition2 来协调T2和T3。
传递< strong> condition1 到T1和T2, condition2 到T2和T3。

因此,我们将在 condition1 中使用 condition1 运行方法,该方法将由T1 发出信号(来自T1的运行方法,T1启动后) /完成它的任务)。

同样在它的run方法中 condition2
上有T3 等待,它将发出信号通过T2(来自T2的run方法,在它启动/完成它的任务之后)。

答案 10 :(得分: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");
    }

}

答案 11 :(得分: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);
  }
}

我认为这可以帮助你。

答案 12 :(得分: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;
}

答案 13 :(得分: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;
}

}

答案 14 :(得分:0)

在使用时尝试以下代码,您可以以这种方式运行n个线程。

image0.gif image1.gif

答案 15 :(得分:0)

在启动线程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();
}

答案 16 :(得分: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()

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