AC という文字を出力する 1 ~ 3 の 3 つのスレッドがある場合、出力順序を保証するにはどうすればよいでしょうか?
スレッドの出力を「ABCABCABC」にしたい
スレッドは独立して実行されるため、スレッドを同期する特別な作業を行わない限り、このような出力は得られません。スレッドをスケジュールするのは OS 次第であるため、独立して実行されている 3 つのスレッドは「ランダムな」出力を出力することが期待されます。
ここの私の解決策: https://gist.github.com/sinujohn/5fa717dfff680634c6b0c2a7eca108acを変更して、これを実現できます。アイデアは、状態を保持するオブジェクトを作成し、そのオブジェクトをすべてのスレッド間で共有することです。共有状態オブジェクトにアクセスする同期ブロックは 1 つだけです。
public class Main {
public static void main(String[] args) throws InterruptedException {
MyState state = new MyState();
final Thread t1 = new Thread(new MyRunnable(10, 'A', state));
final Thread t2 = new Thread(new MyRunnable(10, 'B', state));
final Thread t3 = new Thread(new MyRunnable(10, 'C', state));
t1.start();
t2.start();
t3.start();
}
}
class MyState {
private char state = 'A';
public char getState() {
return state;
}
public void incrState() {
switch(state) {
case 'A':
state = 'B';
return;
case 'B':
state = 'C';
return;
default:
state = 'A';
}
}
}
class MyRunnable implements Runnable {
private final int max;
private final char value;
private final MyState state;
MyRunnable(int max, char value, MyState state) {
this.max = max;
this.value = value;
this.state = state;
}
@Override
public void run() {
int count = 0;
while(count < max) {
synchronized (this.state) {
if (this.state.getState() == this.value) {
System.out.print(value);
count++;
this.state.incrState();
}
}
}
}
}
public class RunningThreadSequentially {
//Runnable task for each thread
private static class Task implements Runnable {
public static int counter=0;
@Override
public void run() {
try {
synchronized(this) {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + " is completed--" + counter ++);
}
} catch (Exception ex) {
}
}
}
public static void main(String args[]) throws InterruptedException {
while(true) {
Thread t1 = new Thread(new Task(), "Thread 1");
Thread t2 = new Thread(new Task(), "Thread 2");
Thread t3 = new Thread(new Task(), "Thread 3");
Thread t4 = new Thread(new Task(), "Thread 4");
Thread t5 = new Thread(new Task(), "Thread 5");
Thread t6 = new Thread(new Task(), "Thread 6");
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
t4.start();
t4.join();
t5.start();
t5.join();
t6.start();
t6.join();
}
}
}
スレッド間通信には、wait と notify を使用できます。ここでは、スレッド間のシグナリングに turn int 変数を使用しています。
public class ThreadInterleaving{
public static void main(String[] args){
MyThread h = new MyThread();
Thread t1 = new Thread(h);
Thread t2 = new Thread(h);
Thread t3 = new Thread(h);
t1.start();
t2.start();
t3.start();
}
}
class MyThread implements Runnable{
public static int turn;
@Override
public void run(){
for(int i =0;i<3;i++){
synchronized(this){
if(turn == 0){
System.out.println("Thread1");
turn =1 ;
notify();
}else{
try{
wait();
}catch(InterruptedException ie){
}
}
if(turn == 1){
System.out.println("Thread2");
turn = 2;
notify();
}else{
try{
wait();
}catch(InterruptedException ie){
}
}
if(turn == 2){
System.out.println("Thread3");
System.out.println("*********");
turn = 0;
notify();
}else{
try{
wait();
}catch(InterruptedException ie){
}
}
}
}
}
}
/*Output
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
Thread1
Thread2
Thread3
*********
*/
public class ThreadOrderTest {
int status = 1;
public static void main(String[] args) {
ThreadOrderTest threadOrderTest = new ThreadOrderTest();
A a = new A(threadOrderTest);
B b = new B(threadOrderTest);
C c = new C(threadOrderTest);
a.start();
b.start();
c.start();
}
}
class A extends Thread {
ThreadOrderTest threadOrderTest;
A(ThreadOrderTest threadOrderTest) {
this.threadOrderTest = threadOrderTest;
}
@Override
public void run() {
try {
synchronized (threadOrderTest) {
for (int i = 0; i < 10; i++) {
while (threadOrderTest.status != 1) {
threadOrderTest.wait();
}
System.out.print("A ");
threadOrderTest.status = 2;
threadOrderTest.notifyAll();
}
}
} catch (Exception e) {
System.out.println("Exception 1 :" + e.getMessage());
}
}
}
class B extends Thread {
ThreadOrderTest threadOrderTest;
B(ThreadOrderTest threadOrderTest) {
this.threadOrderTest = threadOrderTest;
}
@Override
public void run() {
try {
synchronized (threadOrderTest) {
for (int i = 0; i < 10; i++) {
while (threadOrderTest.status != 2) {
threadOrderTest.wait();
}
System.out.print("B ");
threadOrderTest.status = 3;
threadOrderTest.notifyAll();
}
}
} catch (Exception e) {
System.out.println("Exception 2 :" + e.getMessage());
}
}
}
class C extends Thread {
ThreadOrderTest threadOrderTest;
C(ThreadOrderTest threadOrderTest) {
this.threadOrderTest = threadOrderTest;
}
@Override
public void run() {
try {
synchronized (threadOrderTest) {
for (int i = 0; i < 10; i++) {
while (threadOrderTest.status != 3) {
threadOrderTest.wait();
}
System.out.println("C ");
threadOrderTest.status = 1;
threadOrderTest.notifyAll();
}
}
} catch (Exception e) {
System.out.println("Exception 3 :" + e.getMessage());
}
}
}
終了を管理するメソッドと、1 つ以上の非同期タスクの進行状況を追跡するための Future を生成できるメソッドを提供する Executor。
ExecutorService をシャットダウンすると、新しいタスクが拒否される可能性があります。ExecutorService をシャットダウンするための 2 つの異なる方法が用意されています。shutdown() メソッドは、以前に送信されたタスクを終了する前に実行できるようにします。一方、shutdownNow() メソッドは、待機中のタスクの開始を防ぎ、現在実行中のタスクを停止しようとします。終了すると、エグゼキュータにはアクティブに実行されているタスクがなく、実行を待っているタスクもなく、新しいタスクを送信することもできません。未使用の ExecutorService をシャットダウンして、そのリソースを再利用できるようにする必要があります。
メソッド submit は、基本メソッド Executor.execute(java.lang.Runnable) を拡張し、実行をキャンセルしたり、完了を待機したりするために使用できる Future を作成して返します。メソッド invokeAny および invokeAll は、タスクのコレクションを実行してから、少なくとも 1 つまたはすべてのタスクが完了するまで待機する、最も一般的に有用な形式の一括実行を実行します。(クラス ExecutorCompletionService を使用して、これらのメソッドのカスタマイズされたバリアントを作成できます。)
Executors クラスは、このパッケージで提供されるエグゼキュータ サービスのファクトリ メソッドを提供します。