2

これは私の非常にナイーブかもしれませんが、Java でスレッド セーフなコレクションを使用している場合、以下のコード例は常に機能し、NullPointerException でクラッシュしないと常に想定していました。残念ながら、スレッド t2 は、2 つのスレッド宣言の下にある containsKey() メソッドと get() メソッドの呼び出しの間にリストからアイテムを削除できるようです。コメント付きのセクションでは、NullPointerException を取得せずにこの問題を処理する方法を示しています。

私の質問は、スレッド セーフ コレクションを使用して Java でこの問題を処理する正しい方法は何ですか? もちろん、ミューテックスや同期ブロックを使用することもできますが、このような方法では、スレッド セーフ コレクションにまつわる多くの利点と使いやすさが損なわれるのではないでしょうか? ミューテックスまたは同期ブロックを使用する必要がある場合、代わりに非スレッド セーフ コレクションを使用できませんか? さらに、(学界では) コードの null 値をチェックすることは悪いプログラミング手法であると常に聞いていました。私はただクレイジーですか?この問題に対する簡単な答えはありますか? 前もって感謝します。

package test;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Test {
    public static void main(String[] args) {
        final Map<Integer, Integer> test = new ConcurrentHashMap<>();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    test.put(0, 0);
                    Thread.yield();
                }
            }           
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    test.remove(0);
                    Thread.yield();
                }
            }           
        });

        t1.start();
        t2.start();

        while(true) {
            if (test.containsKey(0)) {
                Integer value = test.get(0);
                System.out.println(value);
            }
            Thread.yield();
        }   

        // OR
//      while(true) {
//          Integer value = test.get(0);
//          if (value != null) {
//              System.out.println(value);
//          }
//          Thread.yield();
//      }           
    }
}
4

4 に答える 4

2

これ

if (test.containsKey(0)) {
     Integer value = test.get(0);
     System.out.println(value);
}

まだアトミックではありません。をチェックした後、スレッドを追加/削除できますcontainsKey

そのスニペットの周りの共有リソースで同期する必要があります。またはあなたのnull後にチェックしてくださいget

内のすべての操作ConcurrentHashMapはスレッド セーフですが、メソッドの境界を超えて拡張することはありません。

于 2013-10-01T15:50:36.123 に答える