スレッドがありT1
、T2
スレッドが後に実行され、スレッドが後に実行さT3
れるようにするにはどうすればよいでしょうか?T2
T1
T3
T2
この質問は私のインタビューで聞かれました。私は答えませんでした。詳しく説明してください。
スレッドがありT1
、T2
スレッドが後に実行され、スレッドが後に実行さT3
れるようにするにはどうすればよいでしょうか?T2
T1
T3
T2
この質問は私のインタビューで聞かれました。私は答えませんでした。詳しく説明してください。
これは、最も単純で愚かなアプローチです。
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 でメソッド create/start T2 を実行し、T2 でメソッド create/start T3 を実行します。
それは、私見ですが、無意味だと思いますが、それは可能です。
Join() を使用したソリューションは、この質問に答えません。スレッドの実行ではなく、スレッドの終了が確実に行われるようにします。面接官がそれを理解できない場合は、とにかく別の仕事を見つける必要があります.
インタビューでは、私の答えは「なぜ*のために?」です。スレッドは通常、あなたが求めていることを正確に回避するために使用されます。
それを行う1つの方法は、次のようなものです。複雑ですが。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();
}
}
...
}
}
スレッド T1、T2、および T3 があります。スレッド T2 が T1 の後に実行され、スレッド T3 が T2 の後に実行されるようにするにはどうすればよいでしょうか? または T1、T2、および T3 の 3 つのスレッドがありますか? JavaでシーケンスT1、T2、T3をどのように保証しますか? 問題は基本的に、T3 が最初に、T2 が 2 番目に、T1 が最後に終了する必要があるということです。スレッド クラスの join() メソッドを使用できます。3 つのスレッドを確実に実行するには、最初に最後のスレッド (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 を取得するかわからないため、スレッドが異なる順序で開始されていることがわかります。これはスレッド スケジューラの決定であるため、何もできません。ただし、スレッドが正しい順序で終了していることがわかります。つまり、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
各スレッド (t1 を除く) の開始時に、先行スレッドで join() を呼び出すようにします。エグゼキューターを (スレッドを直接使用する代わりに) 使用することも別のオプションです。セマフォの使用を検討することもできます。T1 は完了時に許可を解放し、T2 は 2 つの許可の取得を試行し、完了したらそれらを解放し、T3 は 3 つの許可の取得を試行する必要があります。join または executor を使用することが推奨される方法です。
たとえば、1 つのスレッドが 1、4、5...2 番目の 2、5、8、3 番目の 3、6、9 などを出力すると、出力は 1、2 になるはずです。 ,3,4,5..... 最初のスレッドは 1 を印刷し、2 番目のスレッドに 2 を印刷する機会を与えます..など、
「one」が 1 を出力するとすぐに、cb.wait を呼び出して 2 つにチャンスを与えます。2 回実行すると、同様の方法で 3 つが呼び出され、続行されます。コードで
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();
}
}
スレッドもランナブルです。それらを順番に実行するだけです:
t1.run();
t2.run();
t3.run();
これは明らかにほとんど関心がありません。
スレッドを並行して実行したい場合、1 つの解決策は、JMM が次のことを保証するため、各スレッドに次のスレッドを開始させることです。
スレッドでの start() の呼び出しは、開始されたスレッドのアクションの前に発生します。
私ははるかに簡単な方法で試しました..待機と通知を使用しました.(前の投稿の循環バリアアプローチとは対照的に)。
これは、1、2、3 の 3 つの状態を取得する「State」クラスを使用します (デフォルトは 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();
}
}
スレッド T2 が T1 の後に実行され、スレッド T3 が T2 の後に実行されるようにするにはどうすればよいでしょうか?
NOTE: Assuming that it is not about scheduling the threads in the required order
条件インターフェイスを使用できます。T1 と T2 を調整するcondition1、T2 と T3 を調整するcondition2という 2つ
の条件を 1 つのLockにバインドする必要があります。condition1を T1 と T2 に渡し、 condition2を T2 と T3 に渡します。
そのため、T2 はrunメソッドで condition1 を 待機し、T1 によって通知されます (T1 がタスクを開始/終了した後、T1 の run メソッドから)。同様に、その実行メソッドで条件2 で T3 を待機させます。これは通知されます。
T2による(T2のrunメソッドから、タスクの開始/終了後)。
作成された他のトレッドの各トレッドで優先キューを作成します。完了後に適用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()
実装は演習として残されているので、次に正しく実行するときは!
その方法で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;
}
}
スレッド 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();
}
package io.hariom.threading;
// 3 つのスレッド 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 { 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");
}
}
これが、シグナリングにCountDownLatchを使用した問題に対する私のアプローチです。
ジョブ信号を T2 に、T2 から T3 に実行した後の T1 スレッド。
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();
}
}