ホームページ  >  記事  >  Java  >  Java の同時実行性の高いマルチスレッド環境で ArrayList、HashSet、HashMap のスレッド セーフを確保するにはどうすればよいでしょうか?

Java の同時実行性の高いマルチスレッド環境で ArrayList、HashSet、HashMap のスレッド セーフを確保するにはどうすればよいでしょうか?

王林
王林転載
2023-05-09 22:49:071460ブラウズ

1.ArrayList のスレッド非安全な解決策

メイン メソッドのコメントの最初の行を開いて数回実行すると、以下に示すような例外情報が表示されます。

Java の同時実行性の高いマルチスレッド環境で ArrayList、HashSet、HashMap のスレッド セーフを確保するにはどうすればよいでしょうか?##これは同時変更の例外です。まず、ArrayList は間違いなくスレッドに対して安全ではありません。この例外の理由は、最初のスレッドが追加を実行するために ArrayList コレクションに入ったばかりである可能性があることです。さらに、このとき、add 操作を実行するために 1 つのスレッドが入り、get 操作を実行するために 3 番目のスレッドが入ったため、読み取りと書き込みが同期できず、最終的に結果が爆発しました。印刷するとき。

解決策 コード内の残りのコメント行を確認してください。

package test.notsafe;
 
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
 
/**
 * 演示ArrayList的线程不安全问题及解决方案
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        //List<String> list = new ArrayList<>();
 
        //解决方法1:使用Vector
        //List<String> list = new Vector<>();
 
        //解决方法2:Collections
        //List<String> list = Collections.synchronizedList(new ArrayList<>());
 
        //解决方法3:CopyOnWriteArrayList
        List<String> list = new CopyOnWriteArrayList<>();
 
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

Java の同時実行性の高いマルチスレッド環境で ArrayList、HashSet、HashMap のスレッド セーフを確保するにはどうすればよいでしょうか?CopyOnWriteArrayList がスレッドのセキュリティの問題をどのように解決するかについての簡単な説明: ソース コードの add(E e) メソッドを見てください:

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

この CopyOnWriteArrayList は、追加操作を実行する前に、まずロックし、次に getArray() を介して元の ArrayList コレクション コンテナーを取得し、次に Arrays.copyOf メソッドを呼び出して元のコンテナーを新しいコンテナーにコピーします (追加する必要があるため)。 (長さは当然 1 です。) 次に、この新しいコンテナに要素を追加します。追加が完了したら、setArray メソッドを呼び出して、元のコンテナの参照がこの新しいコンテナを指すようにします。これを行う利点は、元のコンテナがどのようなものであっても、新しいコンテナに要素を追加します。また、他のスレッドが要素を取得して読み取りたい場合でも、元のコンテナから読み取ることができます (つまり、複数のスレッドが同時に読み取ることができます)。 ; 他のスレッドが追加したい場合は、他のスレッドが完了するのを待ってから、元のコンテナの参照を新しいコンテナにポイントする必要があります。

CopyOnWrite コンテナは、読み取りと書き込みに関しては 2 つの異なるコンテナであり、読み取りと書き込みを分離するという考え方も使用されています。

2. HashSet のスレッド非安全な解決策

ここで新しい HashSet である場合、上記の ArrayList と同じ同時変更例外が発生する可能性があります。解決策については、コード内のコメントを参照してください。

package test.notsafe;
 
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
 
/**
 * 演示HashSet的线程不安全问题及解决方案
 */
public class ThreadDemo3 {
    public static void main(String[] args) {
        //Set<String> set = new HashSet<>();
 
        //解决方法1:Collections
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());
 
        //解决方法2:CopyOnWriteArraySet
        Set<String> set = new CopyOnWriteArraySet<>();
 
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

3. HashMap のスレッド非安全なソリューション

package test.notsafe;
 
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * 演示HashMap的线程不安全问题及解决方案
 */
public class ThreadDemo4 {
    public static void main(String[] args) {
        //Map<String,Object> map = new HashMap<>();
 
        //解决方法1:Collections
        //Map<String,Object> map = Collections.synchronizedMap(new HashMap<>());
 
        //解决方法2:ConcurrentHashMap
        Map<String,Object> map = new ConcurrentHashMap<>();
 
        for (int i = 0; i < 10; i++) {
            String key = String.valueOf(i);
            new Thread(() -> {
                map.put(key,UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }
}

以上がJava の同時実行性の高いマルチスレッド環境で ArrayList、HashSet、HashMap のスレッド セーフを確保するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。