22

有线程T1T2T3如何保证线程T2后运行T1和线程T3后运行T2

这个问题在我的采访中被问到。我没有回答。请详细说明。

4

18 回答 18

29

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

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();
于 2012-07-18T15:36:26.067 回答
6

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

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

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

在一次采访中,我的回答是'为了*为什么?线程通常用于避免您要问的内容!'。

于 2012-07-18T16:54:45.427 回答
5

一种方法是如下所示。虽然很复杂。您可能希望为此使用java.util.concurrent.CyclicBarrier该类。

每个线程完成后设置布尔值并通知下一个线程继续。即使它是一AtomicBoolean门课,我们也需要这样synchronized我们才能做到。wait()notify()

传入锁对象或者可能有一个begin()方法会更干净T2T3因此我们可以将锁隐藏在这些对象中。

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();
            }
        }
        ...
    }
}
于 2012-07-18T15:49:00.460 回答
4

有线程T1、T2、T3,如何保证线程T2在T1之后运行,线程T3在T2之后运行呢?OR 有三个线程 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。它是线程调度程序的决定,所以我们无能为力。但是,您可以看到线程以正确的顺序完成,即 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

于 2018-02-05T07:02:23.243 回答
3

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

于 2012-07-18T15:35:38.913 回答
3

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

我使用cyclebarriers进行了尝试。一旦“一个”打印出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();
    }
}
于 2013-01-22T19:45:58.287 回答
3

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

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

这显然兴趣不大。

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

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

于 2012-07-18T15:27:11.777 回答
1

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

它使用一个“状态”类......它获得三种状态:1、2、3。(默认为 3)。在 3 时触发 t1,在 1 时触发 t2,在 2 时触发 t3,以此类推。

类:State// 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();

        }
    }
于 2015-07-28T06:14:35.887 回答
1

我们如何确保线程 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。 因此,我们将在它的 run 方法中 让 T2在condition1上等待,这将由 T1发出信号(来自 T1 的 run 方法,在 T1 开始/完成其任务之后)。同样在它的 run 方法中让 T3在condition2上等待,这将发出信号



通过 T2(来自 T2 的 run 方法,在它开始/完成它的任务之后)。

于 2017-11-18T20:14:05.453 回答
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();
}
于 2014-05-20T07:00:06.143 回答
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()

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

于 2012-07-18T15:28:41.690 回答
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;
    }
}
于 2015-08-03T10:37:19.697 回答
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;
}

}
于 2016-04-28T08:49:42.190 回答
0

通过使用 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");
    }

}
于 2017-02-10T05:58:54.810 回答
0

concurrent 包有更好的类来使用共享对象。其中一种方法是这样的。

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;
}
于 2016-04-30T15:02:20.960 回答
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();

}

}

类 MyRunnable 实现 Runnable { Thread 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");
}

}

于 2021-03-12T12:06:32.540 回答
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);
  }
}

我想这可以帮助你。

于 2016-11-28T11:00:03.453 回答
0

这是我使用CountDownLatch来解决问题的方法。

T1 线程在完成其工作后向 T2 发出信号,T2 向 T3 发出信号。


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

    CountDownLatch c1 = new CountDownLatch(1);
    CountDownLatch c2 = new CountDownLatch(1);
    Thread T1 = new Thread(new Runnable() {

      @Override
      public void run() {
        System.out.println("T1");
        c1.countDown();
      }
    });
    Thread T2 = new Thread(new Runnable() {
      @Override
      public void run() {
        //should listen to something from T1
        try {
          c1.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("T2");
        c2.countDown();
      }
    });
    Thread T3 = new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          c2.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        System.out.println("T3");
      }
    });

    T1.start();
    T3.start();
    T2.start();
  }
}
于 2022-01-23T15:50:44.227 回答