[407] Re:synchronizedメソッドの“変なこと”
投稿者:(ぱ)
2007/02/20 02:13:25
>こんにちは。はじめまして。
はじめまして。書き込みありがとうございます。
>もしよろしければ、可能性として起こりうる"変なこと"をご教示願えませんでしょうか?
>getとsetが分かれていたり、setのXとYが分かれていたりしていたのでは、
というのが一応ヒントというか根拠のつもりです。
簡単な方から。
◎setのXとYが分かれていたりしていたのでは…
現在(100, 100)であるPointを、(200, 200)に移動させたかったとしましょう。
そのために、
p.setX(200);
p.setY(200);
と書くと、setX()してからsetY()するまでの間、一時的に(200, 100)という状態になり、
この状態が他スレッドから見えてしまいます。
◎getとsetが分かれていたり…
ふたつのスレッドA, Bが以下のようにxをインクリメントしようとすると、
x = p.getX(); // スレッドA ←(1)
x = p.getX(); // スレッドB ←(2)
p.setX(x+1); // スレッドA ←(3)
p.setX(x+1); // スレッドB ←(4)
(3)でスレッドAがインクリメントした結果が(4)で上書きされてしまい、
ふたつのスレッドがひとつずつインクリメントしているはずなのに、
結局xは1しか増えないことになります。
ひとつめの問題は仕様だと言い張ることも可能かもしれませんが、
ふたつめの問題はおそらく致命的でしょう。
結局、マルチスレッドで正しくプログラムを動かしたいのであれば、
Pointのような低レベルなクラスで、個々のメソッドに機械的にsynchronizedを
つけても意味がなく、アプリケーションのレベルで対処しなければなりません。
この手の問題は標準のクラスライブラリにもあって、古いコレクションクラス
(Vectorなど)は、メソッドごとにちまちまとsynchronizedを付けていますが、
現実問題としてこれは無意味であり、後継のArrayListなどでは外されたわけです。
// ループが回っている間に別スレッドでremove()とかされると例外が発生する
size = v.size();
for (int i = 0; i < size; i++) {
Object o = v.get(i);
}
でも今Googleしてみたら、「シングルスレッドでよいときは効率向上のために
ArrayListを使い、スレッドセーフにしたければVectorを使うべし」と解説している
ページの多いこと…
あんまり理解されてないことなんですかねえ。