目次
CopyOnWriteコンテナとは
CopyOnWriteArrayListの実装原理
CopyOnWriteのアプリケーションシナリオ
CopyOnWriteのデメリット
ホームページ Java &#&チュートリアル Java並行プログラミング:並行コンテナCopyOnWriteArrayListの実装原理

Java並行プログラミング:並行コンテナCopyOnWriteArrayListの実装原理

Jul 30, 2018 am 11:41 AM
マルチスレッド化 同時

COWと呼ばれるCopy-On-Writeは、プログラミングで使用される最適化戦略です。基本的な考え方は、全員が最初から同じコンテンツを共有しており、誰かがコンテンツを変更したい場合は、そのコンテンツをコピーして新しいコンテンツを作成し、それを変更するという一種の遅延戦略です。 JDK1.5 以降、Java 同時実行パッケージは、CopyOnWrite メカニズムを使用して実装された 2 つの同時コンテナ (CopyOnWriteArrayList と CopyOnWriteArraySet) を提供します。 CopyOnWrite コンテナは非常に便利で、多くの同時シナリオで使用できます。

CopyOnWriteコンテナとは

CopyOnWriteコンテナとは、書き込み時にコピーされるコンテナです。一般に理解されているのは、要素をコンテナに追加するとき、要素を現在のコンテナに直接追加するのではなく、まず現在のコンテナをコピーして新しいコンテナを作成し、要素を追加した後、その新しいコンテナに要素を追加するということです。次に、元のコンテナの参照が新しいコンテナを指すようにします。この利点は、現在のコンテナーは要素を追加しないため、ロックせずに CopyOnWrite コンテナーで同時読み取りを実行できることです。したがって、CopyOnWriteコンテナも読み書き分離の考え方であり、読み書きは別のコンテナです。

CopyOnWriteArrayListの実装原理

CopyOnWriteArrayListを使用する前に、ソースコードを読んでどのように実装されているかを理解しましょう。次のコードは、CopyOnWriteArrayList の add メソッドの実装 (CopyOnWriteArrayList に要素を追加する) です。追加するときにロックする必要があることがわかります。そうしないと、複数のスレッドで書き込むときに N 個のコピーがコピーされます。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

     * Appends the specified element to the end of this list.

     *

     * @param e element to be appended to this list

     * @return <tt>true</tt> (as specified by {@link Collection#add})

     */

    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 にデータを追加している場合、書き込み時に古い CopyOnWriteArrayList がロックされないため、読み取りでは引き続き古いデータが読み取られます。

1

2

3

public E get(int index) {

    return get(getArray(), index);

}

CopyOnWriteMap は JDK では提供されていません。CopyOnWriteArrayList を参照して実装できます。基本的なコードは次のとおりです。

12
3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

import java.util.Collection;

import java.util.Map;

import java.util.Set;

public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {

    private volatile Map<K, V> internalMap;

    public CopyOnWriteMap() {

        internalMap = new HashMap<K, V>();

    }

    public V put(K key, V value) {

        synchronized (this) {

            Map<K, V> newMap = new HashMap<K, V>(internalMap);

            V val = newMap.put(key, value);

            internalMap = newMap;

            return val;

        }

    }

    public V get(Object key) {

        return internalMap.get(key);

    }

    public void putAll(Map<? extends K, ? extends V> newData) {

        synchronized (this) {

            Map<K, V> newMap = new HashMap<K, V>(internalMap);

            newMap.putAll(newData);

            internalMap = newMap;

        }

    }

}

CopyOnWrite メカニズムを理解していれば、実装は非常に簡単です。さまざまな CopyOnWrite コンテナを実装して、さまざまなアプリケーション シナリオで使用できます。

CopyOnWriteのアプリケーションシナリオ

CopyOnWrite同時コンテナは、読み取りが多く書き込みが少ない同時シナリオで使用されます。たとえば、ホワイトリスト、ブラックリスト、製品カテゴリへのアクセスと更新のシナリオでは、ユーザーはこの Web サイトの検索ボックスにキーワードを入力してコンテンツを検索しますが、一部のキーワードは検索できません。検索できないキーワードはブラックリストに登録され、毎晩更新されます。ユーザーが検索を行うと、現在のキーワードがブラックリストに含まれているかどうかがチェックされ、含まれている場合は検索を実行できないというメッセージが表示されます。実装コードは次のとおりです:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

package com.ifeve.book;

import java.util.Map;

import com.ifeve.book.forkjoin.CopyOnWriteMap;

/**

 * 黑名单服务

 *

 * @author fangtengfei

 *

 */

public class BlackListServiceImpl {

    private static CopyOnWriteMap<String, Boolean> blackListMap = new CopyOnWriteMap<String, Boolean>(

            1000);

    public static boolean isBlackList(String id) {

        return blackListMap.get(id) == null false true;

    }

    public static void addBlackList(String id) {

        blackListMap.put(id, Boolean.TRUE);

    }

コード>    /**

     * 批量添加黑名单

     *

     * @param ids

     */

    public static void addBlackList(Map<String,Boolean> ids) {

        blackListMap.putAll(ids);

    }

}

コードは非常にシンプルですが、CopyOnWriteMapを使用する際に注意する必要があることが2つあります:

1. 展開のオーバーヘッドを削減します。実際のニーズに応じて CopyOnWriteMap のサイズを初期化し、書き込み中の CopyOnWriteMap 拡張のオーバーヘッドを回避します。

2. 一括追加を使用します。追加するたびにコンテナがコピーされるため、追加の数を減らすことでコンテナのコピー回数を減らすことができます。たとえば、上記のコードでは addBlackList メソッドを使用します。

CopyOnWriteのデメリット

CopyOnWriteコンテナには多くの利点がありますが、メモリ使用量とデータの一貫性という2つの問題もあります。そのため、開発時には注意が必要です。

メモリ使用量の問題。 CopyOnWrite のコピーオンライト メカニズムにより、書き込み操作が実行されると、古いオブジェクトと新しく書き込まれたオブジェクトという 2 つのオブジェクトが同時にメモリ内に常駐します (注: コピー中は、メモリ内の参照のみが保持されます)。コンテナは書き込み時にのみコピーされ、新しいオブジェクトが作成されて新しいコンテナに追加されますが、古いコンテナ内のオブジェクトはまだ使用されているため、オブジェクト メモリのコピーが 2 つ存在します。これらのオブジェクトが約 200M などの比較的大量のメモリを占有している場合、さらに 100M のデータを書き込むと 300M のメモリが占​​有されるため、Yong GC と Full GC が頻繁に発生する可能性があります。以前は、CopyOnWrite メカニズムを使用して大きなオブジェクトを毎晩更新するサービスをシステムで使用していました。その結果、毎晩 15 秒のフル GC が発生し、アプリケーションの応答時間も長くなりました。

メモリ使用量の問題に対処するには、コンテナ内の要素を圧縮することで、大きなオブジェクトのメモリ消費を減らすことができます。たとえば、要素がすべて 10 進数の場合、36 桁または 64 桁に圧縮することを検討できます。数字。または、CopyOnWrite コンテナを使用せず、ConcurrentHashMap などの他の同時コンテナを使用します。

データの整合性の問題。 CopyOnWrite コンテナはデータの最終的な整合性のみを保証できますが、データのリアルタイムの整合性は保証できません。したがって、書き込まれたデータをすぐに読み出したい場合は、CopyOnWrite コンテナを使用しないでください。

関連記事:

Java 同時プログラミング: CountDownLatch、CyclicBarrier、およびセマフォ

[JAVA 同時プログラミングの実践] ロックシーケンシャルデッドロック

関連ビデオ:

Java マルチスレッドと同時実行ライブラリの詳細アプリケーションビデオチュートリアル

以上がJava並行プログラミング:並行コンテナCopyOnWriteArrayListの実装原理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++ 関数の例外とマルチスレッド: 同時環境でのエラー処理 C++ 関数の例外とマルチスレッド: 同時環境でのエラー処理 May 04, 2024 pm 04:42 PM

C++ での関数例外処理は、マルチスレッド環境でスレッドの安全性とデータの整合性を確保するために特に重要です。 try-catch ステートメントを使用すると、特定の種類の例外が発生したときにそれをキャッチして処理し、プログラムのクラッシュやデータの破損を防ぐことができます。

Golang API 設計における同時実行性とコルーチンの適用 Golang API 設計における同時実行性とコルーチンの適用 May 07, 2024 pm 06:51 PM

同時実行性とコルーチンは、GoAPI 設計で次の目的で使用されます。 高パフォーマンス処理: 複数のリクエストを同時に処理してパフォーマンスを向上させます。非同期処理: コルーチンを使用してタスク (電子メールの送信など) を非同期に処理し、メインスレッドを解放します。ストリーム処理: コルーチンを使用して、データ ストリーム (データベース読み取りなど) を効率的に処理します。

PHPでマルチスレッドを実装するにはどうすればよいですか? PHPでマルチスレッドを実装するにはどうすればよいですか? May 06, 2024 pm 09:54 PM

PHP マルチスレッドとは、1 つのプロセスで複数のタスクを同時に実行することを指します。これは、独立して実行されるスレッドを作成することによって実現されます。 PHP の Pthreads 拡張機能を使用して、マルチスレッド動作をシミュレートできます。インストール後、Thread クラスを使用してスレッドを作成および開始できます。たとえば、大量のデータを処理する場合、データを複数のブロックに分割し、対応する数のスレッドを作成して同時処理することで効率を向上させることができます。

C++ のマルチスレッドで共有リソースを処理するにはどうすればよいですか? C++ のマルチスレッドで共有リソースを処理するにはどうすればよいですか? Jun 03, 2024 am 10:28 AM

ミューテックスは C++ でマルチスレッド共有リソースを処理するために使用されます。std::mutex を通じてミューテックスを作成します。 mtx.lock() を使用してミューテックスを取得し、共有リソースへの排他的アクセスを提供します。ミューテックスを解放するには mtx.unlock() を使用します。

マルチスレッド環境における C++ メモリ管理の課題と対策? マルチスレッド環境における C++ メモリ管理の課題と対策? Jun 05, 2024 pm 01:08 PM

マルチスレッド環境では、C++ メモリ管理はデータ競合、デッドロック、メモリ リークなどの課題に直面します。対策には次のものが含まれます: 1. ミューテックスやアトミック変数などの同期メカニズムの使用、 2. ロックフリーのデータ構造の使用、 4. (オプション) ガベージ コレクションの実装。

C++ でマルチスレッド プログラムをテストするための課題と戦略 C++ でマルチスレッド プログラムをテストするための課題と戦略 May 31, 2024 pm 06:34 PM

マルチスレッド プログラムのテストは、非再現性、同時実行エラー、デッドロック、可視性の欠如などの課題に直面しています。戦略には以下が含まれます。 単体テスト: 各スレッドの単体テストを作成して、スレッドの動作を検証します。マルチスレッド シミュレーション: シミュレーション フレームワークを使用して、スレッド スケジューリングを制御しながらプログラムをテストします。データ競合の検出: valgrind などのツールを使用して、潜在的なデータ競合を見つけます。デバッグ: デバッガー (gdb など) を使用して、ランタイム プログラムのステータスを調べ、データ競合の原因を見つけます。

Go 同時関数の単体テストのガイド Go 同時関数の単体テストのガイド May 03, 2024 am 10:54 AM

並行関数の単体テストは、同時環境での正しい動作を確認するのに役立つため、非常に重要です。同時実行機能をテストするときは、相互排他、同期、分離などの基本原則を考慮する必要があります。並行機能は、シミュレーション、競合状態のテスト、および結果の検証によって単体テストできます。

C++ テクノロジにおける例外処理: マルチスレッド環境で例外を正しく処理するにはどうすればよいですか? C++ テクノロジにおける例外処理: マルチスレッド環境で例外を正しく処理するにはどうすればよいですか? May 09, 2024 pm 12:36 PM

マルチスレッド C++ では、例外処理は適時性、スレッドの安全性、明確性という原則に従います。実際には、ミューテックスまたはアトミック変数を使用することで、例外処理コードのスレッド セーフを確保できます。さらに、例外処理コードの再入性、パフォーマンス、テストを考慮して、コードがマルチスレッド環境で安全かつ効率的に実行されることを確認してください。

See all articles