Javaメソッドパラメータのマルチスレッド環境での同期
JDKのjava.util.Collectionsクラスでは、いくつかの便利な操作セットの方法が提供されています.例:
これらの方法はすべて非スレッドで安全です.マルチスレッド環境では、あるスレッドがListをソートしていると仮定し、別のスレッドが同時にListから要素を削除すると、異常が発生する可能性が高い.
上記の方法をどのように修正してスレッドを安全にしますか?
codingの前に、いくつかの前提を理解する必要があります.
1.クラスライブラリとして、他の開発者がこの方法をどのように使用するかは予想できません.すなわち,パラメータとして渡されたリストを他の開発者がロックされていない環境で修正すると,そのオブジェクトを簡単にロックしても,そのオブジェクトを保護することはできない.
2.クラス全体またはインスタンス全体にロックをかけると、コストがかかりすぎて問題を解決できません1.
したがって、例えばスレッドセキュリティのソート方法を記述するには、まず、ソートするリストがスレッドセキュリティである必要があります.例えば、リストはパラメータとして適切ではなく(synchronizedであることは確認できません)、Vectorに置き換える必要があります.つまり、メソッドは次のように変更する必要があります.
次に、ソート操作が他のスレッドによって中断されないことを保証します.つまり、ソート操作にはロックが必要です.
この二つの条件は一つ欠けてはいけない.テストコードは次のとおりです(TestSyncParam.java):
実行結果は次のとおりです.
Start bubble sorting.Thread[main,5,main]
Trying to remove first element. - Thread[Thread-1,5,main]
Bubble sorting done.Thread[main,5,main]
Removed '2', size: 11 - Thread[Thread-1,5,main]
要するに、マルチスレッド環境では、共有リソースをメソッドパラメータとして推奨しません.必要に応じて、リソースオブジェクトはスレッドセキュリティでなければなりません.メソッドの実装では、デッドロックを回避する必要があります.
public static void reverse(List<?> list)
public static void shuffle(List<?> list)
public static <T extends Comparable<? super T>> void sort(List<T> list)
など.これらの方法はすべて非スレッドで安全です.マルチスレッド環境では、あるスレッドがListをソートしていると仮定し、別のスレッドが同時にListから要素を削除すると、異常が発生する可能性が高い.
上記の方法をどのように修正してスレッドを安全にしますか?
codingの前に、いくつかの前提を理解する必要があります.
1.クラスライブラリとして、他の開発者がこの方法をどのように使用するかは予想できません.すなわち,パラメータとして渡されたリストを他の開発者がロックされていない環境で修正すると,そのオブジェクトを簡単にロックしても,そのオブジェクトを保護することはできない.
2.クラス全体またはインスタンス全体にロックをかけると、コストがかかりすぎて問題を解決できません1.
したがって、例えばスレッドセキュリティのソート方法を記述するには、まず、ソートするリストがスレッドセキュリティである必要があります.例えば、リストはパラメータとして適切ではなく(synchronizedであることは確認できません)、Vectorに置き換える必要があります.つまり、メソッドは次のように変更する必要があります.
public <T> void sort(final Vector<T> list);
次に、ソート操作が他のスレッドによって中断されないことを保証します.つまり、ソート操作にはロックが必要です.
public <T> void sort(finalVector<T> list){
synchronized (list) {
//perform sorting on the list.
}
}
この二つの条件は一つ欠けてはいけない.テストコードは次のとおりです(TestSyncParam.java):
import java.util.Vector;
public class TestSyncParam {
public void sort(Vector<Integer> list) {
synchronized (list) {
System.out.println("Start bubble sorting." + Thread.currentThread());
for (int i = 0; i < list.size(); i++) {
for (int j = list.size() - 1; j > i; j--) {
if (list.get(j) < list.get(j - 1)) {
int tmp = list.get(j - 1);
list.set(j - 1, list.get(j));
list.set(j, tmp);
}
try {
// slow down to give other threads a chance to touch 'list'
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
}
System.out.println("Bubble sorting done." + Thread.currentThread());
}//end of sync
}
public static void main(String[] args) {
int[] ii = new int[] { 12, 5, 18, 3, 50, 34, 4, 8, 11, 3, 25, 2 };
final Vector<Integer> list = new Vector<Integer>();
for (int i : ii)
list.add(i);
Runnable r1 = new Runnable() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println("Trying to remove first element. - " + Thread.currentThread());
Integer i = list.remove(0);
System.out.println("Removed '" + i + "', size: "+list.size()+" - " + Thread.currentThread());
}
};
TestSyncParam tsp = new TestSyncParam();
new Thread(r1).start();
tsp.sort(list);
}
}
実行結果は次のとおりです.
Start bubble sorting.Thread[main,5,main]
Trying to remove first element. - Thread[Thread-1,5,main]
Bubble sorting done.Thread[main,5,main]
Removed '2', size: 11 - Thread[Thread-1,5,main]
要するに、マルチスレッド環境では、共有リソースをメソッドパラメータとして推奨しません.必要に応じて、リソースオブジェクトはスレッドセキュリティでなければなりません.メソッドの実装では、デッドロックを回避する必要があります.