JAva同時(二十八)同時乱数,原子変数,同時集合
3552 ワード
げんしへんすう
java.util.concurrent.atomicパケットは,単一変数を原子操作するクラスを定義する.原子変数クラスは、整数またはオブジェクト参照上の細粒度原子操作(したがって、より伸縮性が高い)を提供し、現代のプロセッサで提供される下位並列原語(例えば、[compare-and-swap]を比較して交換する)を使用する.すべてのクラスはgetメソッドとsetメソッドを提供し、volatile変数のように原子クラスを読み書きできます.すなわち、同じ変数上のset操作は、任意の後続のget操作に対してhappens−before関係を有する.原子のcompareAndSet法にもメモリ整合性の特徴があり,整数原子変数に適用される単純な原子アルゴリズムのようなものである.
このパッケージの使用方法を確認するには、スレッド干渉を実証するために最初に使用されたCounterクラスに戻ります.
同期を使用することは、SynchronizedCounterのようなCounterクラスをスレッドで安全にする方法です.
この単純なクラスでは、同期は許容可能なソリューションです.しかし、より複雑なクラスでは、同期を必要としない活発さの影響を回避したい場合があります.intをAtomicIntegerに置き換えると、AtomicCounterなどのスレッド干渉を同期せずに阻止できます.
同時集合
ConcurrentHashMap
セグメントロック(Lock Striping)と呼ばれるより細かい粒度のロックが使用される.このメカニズムでは、任意の数のリードスレッドが同時にMapにアクセスでき、リード動作を実行するスレッドとライト動作を実行するスレッドが同時にMapにアクセスでき、一定数のライトスレッドが同時にMapを修正することができる.
反復時にConcurrentModificationExceptionは放出されません.反復器は「即時失敗」ではなく「弱い一貫性」を持っています.sizeは推定値を返します.
ConcurrentNavigableMapはConcurrentMapのサブインタフェースであり、近似整合をサポートする.ConcurrentNavigableMapの標準実装はTreeMapの同時モードであるConcurrentSkipListMapである.ConcurrentSkipListMapとConcurrentSkipListSetは、同期したSortedMapとSortedSetの同時代替品として使用されます.
CopyOnWriteArrayList
変更するたびに、新しいコンテナのコピーが作成され、再パブリッシュされ、レプリケーションが実行されます.[書き込み時にコピー](Copy On Write)は、反復器に戻ってもConcurrentModificationExceptionは放出されず、反復器の作成時の要素と完全に一致し、その後の変更操作の影響を考慮する必要はありません.
同時乱数
JDK 7でjava.util.concurrentには、アプリケーションが複数のスレッドまたはForkJoinTasksで乱数を使用することを望んでいる場合に便利なクラスが含まれています.同時アクセスの場合、Mathの代わりにTheadLocalRandomを使用します.random()は、競合を低減し、より良いパフォーマンスを得ることができます.それを呼び出すだけだcurrent()を呼び出し、そのメソッドの1つを呼び出して乱数を取得すればよい.次に例を示します.
java.util.concurrent.atomicパケットは,単一変数を原子操作するクラスを定義する.原子変数クラスは、整数またはオブジェクト参照上の細粒度原子操作(したがって、より伸縮性が高い)を提供し、現代のプロセッサで提供される下位並列原語(例えば、[compare-and-swap]を比較して交換する)を使用する.すべてのクラスはgetメソッドとsetメソッドを提供し、volatile変数のように原子クラスを読み書きできます.すなわち、同じ変数上のset操作は、任意の後続のget操作に対してhappens−before関係を有する.原子のcompareAndSet法にもメモリ整合性の特徴があり,整数原子変数に適用される単純な原子アルゴリズムのようなものである.
このパッケージの使用方法を確認するには、スレッド干渉を実証するために最初に使用されたCounterクラスに戻ります.
public class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
同期を使用することは、SynchronizedCounterのようなCounterクラスをスレッドで安全にする方法です.
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
この単純なクラスでは、同期は許容可能なソリューションです.しかし、より複雑なクラスでは、同期を必要としない活発さの影響を回避したい場合があります.intをAtomicIntegerに置き換えると、AtomicCounterなどのスレッド干渉を同期せずに阻止できます.
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private AtomicInteger c = new AtomicInteger(0);
public void increment() {
c.incrementAndGet();
}
public void decrement() {
c.decrementAndGet();
}
public int value() {
return c.get();
}
}
同時集合
ConcurrentHashMap
セグメントロック(Lock Striping)と呼ばれるより細かい粒度のロックが使用される.このメカニズムでは、任意の数のリードスレッドが同時にMapにアクセスでき、リード動作を実行するスレッドとライト動作を実行するスレッドが同時にMapにアクセスでき、一定数のライトスレッドが同時にMapを修正することができる.
反復時にConcurrentModificationExceptionは放出されません.反復器は「即時失敗」ではなく「弱い一貫性」を持っています.sizeは推定値を返します.
ConcurrentNavigableMapはConcurrentMapのサブインタフェースであり、近似整合をサポートする.ConcurrentNavigableMapの標準実装はTreeMapの同時モードであるConcurrentSkipListMapである.ConcurrentSkipListMapとConcurrentSkipListSetは、同期したSortedMapとSortedSetの同時代替品として使用されます.
import java.util.Map;
public interface ConcurrentMap<K, V> extends Map<K, V> {
/**
* K
* @param key
* @param value
* @return
*/
V putIfAbsent(K key, V value);
/**
* K V
* @param key
* @param value
* @return
*/
boolean remove(Object key, Object value);
/**
* K oldValue newValue
* @param key
* @param oldValue
* @param newValue
* @return
*/
boolean replace(K key, V oldValue, V newValue);
/**
* K newValue
* @param key
* @param value
* @return
*/
V replace(K key, V value);
}
CopyOnWriteArrayList
変更するたびに、新しいコンテナのコピーが作成され、再パブリッシュされ、レプリケーションが実行されます.[書き込み時にコピー](Copy On Write)は、反復器に戻ってもConcurrentModificationExceptionは放出されず、反復器の作成時の要素と完全に一致し、その後の変更操作の影響を考慮する必要はありません.
同時乱数
JDK 7でjava.util.concurrentには、アプリケーションが複数のスレッドまたはForkJoinTasksで乱数を使用することを望んでいる場合に便利なクラスが含まれています.同時アクセスの場合、Mathの代わりにTheadLocalRandomを使用します.random()は、競合を低減し、より良いパフォーマンスを得ることができます.それを呼び出すだけだcurrent()を呼び出し、そのメソッドの1つを呼び出して乱数を取得すればよい.次に例を示します.
int r = ThreadLocalRandom.current().nextInt(4,77);