端的に言えば、同期メソッドを使用して、Javaで並行性をテストするコードを作成しました。
コード:
public class ThreadTraining {
public static class Value {
private static int value;
public static synchronized void Add() {
value++;
}
public static synchronized void Sub() {
value--;
}
public static synchronized int Get() {
return value;
}
}
public static class AddT implements Runnable {
public static String name;
public AddT(String n) {
name = n;
}
@Override
public void run() {
while (Value.Get() < 100) {
int prev = Value.Get();
Value.Add();
System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}
}
}
public static class SubT implements Runnable {
public static String name;
public SubT(String n) {
name = n;
}
@Override
public void run() {
while (Value.Get() > (-100)) {
int prev = Value.Get();
Value.Sub();
System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}
}
}
public static void main(String[] args) {
Thread threads[] = new Thread[3];
for (int i = 0; i < 4; i++) {
if (i % 2 == 0) {
threads[i] = new Thread(new AddT("Adder - Thread #" + i));
} else {
threads[i] = new Thread(new SubT("Subtractor - Thread #" + i));
}
threads[i].start();
}
}
}
このコードは、 「同じオブジェクトで同期されたメソッドを2回呼び出してインターリーブすることはできない」という事実にもかかわらず、実行の信頼性が低くなっています。(出典:Oracleの並行性チュートリアル-同期メソッド)、次のような信頼性の低い出力を提供します:(出力のパターン化されていない変更は、信頼性の低い動作だけでなく、「...」行の間に示されます)
-----[Thread #0 - Adder] has been created!
=====[Thread #0 - Adder] has been started!
-----[Thread #1 - Subtractor] has been created!
[Thread #0 - Adder] - changed value from 0 to 1
[Thread #0 - Adder] - changed value from 1 to 2
[Thread #0 - Adder] - changed value from 2 to 3
...\*goes on, adding as expected, for some lines*\
[Thread #0 - Adder] - changed value from 83 to 84
[Thread #0 - Adder] - changed value from 84 to 85
-----[Thread #2 - Adder] has been created!
=====[Thread #1 - Subtractor] has been started!
[Thread #0 - Adder] - changed value from 85 to 86
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 85 to 84
...\*goes on, subtracting as expected, for some lines*\
[Thread #1 - Subtractor] - changed value from -98 to -99
[Thread #1 - Subtractor] - changed value from -99 to -100 \*This thread ends here, as it reaches the state where (value>(-100))==false*\
=====[Thread #2 - Adder] has been started!
[Thread #2 - Adder] - changed value from -100 to -99
[Thread #2 - Adder] - changed value from -99 to -98
[Thread #2 - Adder] - changed value from -98 to -97
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from -67 to -66
[Thread #2 - Adder] - changed value from -66 to -65
-----[Thread #3 - Subtractor] has been created!
=====[Thread #3 - Subtractor] has been started!
[Thread #3 - Subtractor] - changed value from -65 to -66
[Thread #3 - Subtractor] - changed value from -66 to -67
...\*goes on as expected...*\
[Thread #3 - Subtractor] - changed value from -71 to -72
[Thread #3 - Subtractor] - changed value from -72 to -73 \*NOTE: From -73 it goes to -74, without a Subtractor-action in between! WTF???*\
[Thread #2 - Adder] - changed value from -74 to -73
[Thread #2 - Adder] - changed value from -73 to -72
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from 98 to 99
[Thread #2 - Adder] - changed value from 99 to 100 \*This adder ends here, adder thread #0 probably ends after next line...but not before doing something crazy!*\
[Thread #0 - Adder] - changed value from 85 to 86 \*What the hell are these values doing here? Oh wait, next lines is...*\
[Thread #3 - Subtractor] - changed value from -73 to -47\*...Holy mother of god!*\
[Thread #3 - Subtractor] - changed value from 100 to 99
[Thread #3 - Subtractor] - changed value from 99 to 98
...
[Thread #3 - Subtractor] - changed value from -98 to -99
[Thread #3 - Subtractor] - changed value from -99 to -100 \*The logical nightmare is finally over.*\
同期されたメソッドの使用は信頼できませんか?それとも実装が間違っていますか?(もしそうなら、それでは何が悪いのですか?そしてそれを修正する方法は?)