6. カンカレンシとは何ですか?
同時実行性は、複数のスレッド間で動作するように最適化された特別なクラスを含む Java のクラス ライブラリです。これらのクラスは 1 つのパッケージにまとめられていますjava.util.concurrent
。それらは、次のように機能に従って概略的に分類できます。 同時 コレクションjava.util
-パッケージの標準のユニバーサル コレクションよりもマルチスレッド環境で効率的に動作するコレクションのセット。コレクション全体へのアクセスをブロックする基本的なラッパーの代わりにCollections.synchronizedList
、データ セグメントのロックが使用されるか、待機なしアルゴリズムを使用してデータの並列読み取り用に作業が最適化されます。 キュー- マルチスレッドをサポートするノンブロッキング キューとブロッキング キュー。ノンブロッキング キューは、スレッドをブロックせずに速度と操作を行えるように設計されています。ブロッキング キューは、キューが空かオーバーフローしている、または空きの「コンシューマー」がないなど、いくつかの条件が満たされない場合に、「プロデューサー」または「コンシューマー」スレッドの「速度を下げる」必要がある場合に使用されます。 シンクロナイザーは、スレッドを同期するための補助ユーティリティです。これらは「並列」コンピューティングにおける強力な武器です。 エグゼキュータ- スレッド プールの作成、非同期タスクのスケジュール設定、および結果の取得のための優れたフレームワークが含まれています。 ロック-基本 的なsynchronized
スレッド同期メカニズムと比較して、より柔軟な代替スレッド同期メカニズムを表します。アトミックス- プリミティブと参照に対するアトミック操作をサポートするクラス。 ソース:wait
notify
notifyAll
7. カンカレンシのどの授業を知っていますか?
この質問に対する答えは、この記事に完全に記載されています。すべてをここに再掲することに意味がないと思うので、私が簡単に知ることができた光栄なクラスについてのみ説明します。 ConcurrentHashMap<K, V> - およびHashtable
のブロックとはsynhronized
異なりHashMap
、データはキーのハッシュに分割されたセグメントの形式で表示されます。その結果、データは単一のオブジェクトではなくセグメントによってアクセスされます。さらに、イテレータは特定の期間のデータを表し、 をスローしませんConcurrentModificationException
。 AtomicBoolean、AtomicInteger、AtomicLong、AtomicIntegerArray、AtomicLongArray - クラス内で、型の 1 つの単純な変数へのアクセスを同期する必要がある場合はどうすればよいでしょうかint
。synchronized
アトミック操作を使用する場合は、 およびを使用して構成を使用できますset/get
。volatile
しかし、新しいクラスを使用すると、さらに優れた結果を得ることができますAtomic*
。CAS を使用しているため、これらのクラスの操作は、 を介して同期する場合よりも高速ですsynchronized/volatile
。さらに、増加/減少だけでなく、指定された量ずつアトミックに追加するメソッドもあります。
8. ConcurrentHashMap クラスはどのように機能しますか?
導入の時点までに、ConcurrentHashMap
Java 開発者は次のハッシュ マップ実装を必要としていました。
- スレッドの安全性
- アクセス中にテーブル全体をロックしない
- 読み取り操作を実行するときにテーブル ロックがないことが望ましい
ConcurrentHashMap
次のとおりです。
-
マップ要素
要素とは異なり
HashMap
、Entry
in はConcurrentHashMap
として宣言されますvolatile
。これは、 JMMの変更による重要な機能です。static final class HashEntry<K, V> { final K key; final int hash; volatile V value; final HashEntry<K, V> next; HashEntry(K key, int hash, HashEntry<K, V> next, V value) { this .key = key; this .hash = hash; this .next = next; this .value = value; } @SuppressWarnings("unchecked") static final <K, V> HashEntry<K, V>[] newArray(int i) { return new HashEntry[i]; } }
-
ハッシュ関数
ConcurrentHashMap
改良されたハッシュ関数も使用されます。HashMap
JDK 1.2ではどうだったかを思い出してください。static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
ConcurrentHashMap JDK 1.5 からのバージョン:
private static int hash(int h) { h += (h << 15) ^ 0xffffcd7d; h ^= (h >>> 10); h += (h << 3); h ^= (h >>> 6); h += (h << 2) + (h << 14); return h ^ (h >>> 16); }
なぜハッシュ関数をより複雑にする必要があるのでしょうか? ハッシュ マップ内のテーブルの長さは 2 の累乗で決まります。バイナリ表現が下位と上位で変わらないハッシュ コードの場合、衝突が発生します。ハッシュ関数の複雑さを増すとこの問題が解決され、マップ内で衝突が発生する可能性が減ります。
-
セグメント
マップは N 個の異なるセグメントに分割されます (デフォルトでは 16、最大値は 16 ビットで 2 の累乗です)。各セグメントは、マップ要素のスレッドセーフなテーブルです。セグメントの数を増やすと、変更操作が複数のセグメントにまたがるようになり、実行時にブロックされる可能性が低くなります。
-
同時実行レベル
このパラメータは、メモリ カードの使用量とカード内のセグメントの数に影響します。
セグメントの数は、concurrencyLevel より大きい 2 の最も近い累乗として選択されます。concurrencyLevel を下げると、書き込み時にスレッドがマップ セグメントをブロックする可能性が高くなります。インジケーターを過大評価すると、メモリの非効率な使用につながります。1 つのスレッドだけがマップを変更し、残りのスレッドが読み取りを行う場合は、値 1 を使用することをお勧めします。
-
合計
主な利点と実装機能は次のとおりです
ConcurrentHashMap
。- マップには次のような
hashmap
インタラクション インターフェイスがあります。 - 読み取り操作はロックを必要とせず、並行して実行されます。
- 多くの場合、書き込み操作はブロックせずに並行して実行できます。
concurrencyLevel
作成時に、読み取りおよび書き込みの統計によって決定される必要なものが示されます。value
マップ要素には次のように宣言された値があります。volatile
- マップには次のような
9. ロッククラスとは何ですか?
共有リソースへのアクセスを制御するには、同期されたオペレーターの代わりにロックを使用できます。ロック機能は にパッケージ化されていますjava.util.concurrent.locks
。まず、スレッドは共有リソースへのアクセスを試みます。フリーの場合は、スレッドにロックが設定されます。作業が完了すると、共有リソースのロックが解放されます。リソースが空いておらず、すでにロックが設定されている場合、スレッドはこのロックが解放されるまで待機します。Lock
ロック クラスは、次のメソッドを定義する インターフェイスを実装します。
void lock():
ロックが取得されるまで待機しますboolean tryLock():
ロックの取得を試みます。ロックが取得された場合は、trueを返します。ロックが取得されない場合は、falseを返します。メソッドとは異なり、lock()
ロックが利用できない場合でもロックの取得を待機しません。void unlock():
ロックを解除しますCondition newCondition():
Condition
現在のロックに関連付けられているオブジェクトを返します
lock()
、共有リソースの操作が終了した後、メソッドが呼び出されunlock()
、ロックが解放されます。このオブジェクトを使用Condition
すると、ブロックを管理できます。原則として、ロックを操作するには、ReentrantLock
パッケージのクラスが使用され、java.util.concurrent.locks.
このクラスは インターフェイス を実装しますLock
。例として小さなプログラムを使用して、Java Lock API の使用を見てみましょう。つまり、Resource
いくつかのスレッド セーフ メソッドと、スレッド セーフが必要ないメソッドを含むクラスがあるとします。
public class Resource {
public void doSomething(){
// пусть здесь происходит работа с базой данных
}
public void doLogging(){
// потокобезопасность для логгирования нам не требуется
}
}
Runnable
次に、インターフェイスを実装し、クラス メソッドを使用する クラスを考えてみましょうResource
。
public class SynchronizedLockExample implements Runnable{
// экземпляр класса Resource для работы с методами
private Resource resource;
public SynchronizedLockExample(Resource r){
this.resource = r;
}
@Override
public void run() {
synchronized (resource) {
resource.doSomething();
}
resource.doLogging();
}
}
次に、 の代わりに Lock API を使用して上記のプログラムを書き直してみましょうsynchronized
。
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// класс для работы с Lock API. Переписан с приведенной выше программы,
// но уже без использования ключевого слова synchronized
public class ConcurrencyLockExample implements Runnable{
private Resource resource;
private Lock lock;
public ConcurrencyLockExample(Resource r){
this.resource = r;
this.lock = new ReentrantLock();
}
@Override
public void run() {
try {
// лочим на 10 секунд
if(lock.tryLock(10, TimeUnit.SECONDS)){
resource.doSomething();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//убираем лок
lock.unlock();
}
// Для логгирования не требуется потокобезопасность
resource.doLogging();
}
}
プログラムからわかるように、tryLock()
スレッドが一定時間だけ待機するようにするメソッドを使用しています。オブジェクトのロックを取得できない場合は、単にログを記録して終了します。もう一つ重要な点があります。try-finally
メソッドがdoSomething()
例外をスローした 場合でもロックが確実に解放されるようにするには、ブロックを使用する必要があります。出典:
11. ミューテックスとは何ですか?
ミューテックスは、スレッド/プロセスを同期するための特別なオブジェクトです。ビジー状態とフリー状態の 2 つの状態を取ることができます。簡単に説明すると、ミューテックスは、busy (true) と free (false) の 2 つの値を取るブール変数です。スレッドがオブジェクトの排他的所有権を必要とする場合、スレッドはそのミューテックスをビジーとしてマークし、その処理が終了すると、そのミューテックスをフリーとしてマークします。ミューテックスは Java のすべてのオブジェクトに付加されます。Java マシンのみがミューテックスに直接アクセスできます。プログラマからは隠蔽されます。12. モニターとは何ですか?
モニターは特別なメカニズム (コードの一部)、つまりミューテックス上のアドオンであり、ミューテックスの正しい動作を保証します。結局のところ、オブジェクトがビジーであることをマークするだけでは十分ではなく、他のスレッドがそのビジー オブジェクトを使用しようとしないようにする必要もあります。Java では、モニターはキーワード を使用して実装されますsynchronized
。同期ブロックを作成すると、Java コンパイラーはそれを 3 つのコードに置き換えます。
- ブロックの先頭に
synchronized
、ミューテックスをビジーとしてマークするコードが追加されます。 - ブロックの最後に、
synchronized
ミューテックスを空きとしてマークするコードが追加されます。 - ブロックの前に、
synchronized
ミューテックスがビジーかどうかをチェックするコードが追加されます。ミューテックスがビジーである場合、スレッドはミューテックスが解放されるまで待機する必要があります。
GO TO FULL VERSION