『JAVA同時プログラミング実戦』第4章対象の組合せ
11872 ワード
4.1スレッドセキュリティのクラスの設計
プログラムリスト4-1 Javaモニタモードを使用したスレッドセキュリティカウンタ
4.2インスタンス閉鎖
プログラムリスト4-2閉鎖機構によりスレッドの安全を確保
4.2.1 Javaモニタモード
プログラムリスト4-3は、プライベートロックによって状態を保護する
プライベートロックオブジェクトは、クライアントコードを使用してロックを取得できないロックをカプセル化できますが、publicメソッドでロックにアクセスして同期ポリシーに参加することができます.
4.2.2例:車両追跡器
プログラムリスト4-4モニタモードによる車両追跡
4.3スレッドセキュリティの依頼
4.3.1委託による車両トラッカー
プログラムリスト4-7スレッドセキュリティをConcurrentHashMapに委任
4.3.2独立した状態変数
プログラムリスト4-9スレッドセキュリティを複数のステータス変数に委任
4.3.3委託が失効した場合
プログラムリスト4-10 NumberRangeクラスはその不変性条件を保護するのに十分ではありません(そうしないでください)
4.3.5例:発行状態の車両追跡器
プログラムリスト4-11スレッドが安全で可変なPointクラス
プログラムリスト4-12最下位状態の車両追跡器を安全に公開する
4.4既存のスレッドセキュリティクラスに機能を追加する
プログラムリスト4-13は、Vectorを拡張し、「なければ追加」メソッドを追加します.
4.4.1クライアントロックメカニズム
プログラムリスト4-14非スレッドセキュリティの「なければ追加」(そうしない)
プログラムリスト4-15は、クライアントのロックによって実現される「なければ追加する」
クライアント・ロックとは、オブジェクトXを使用するクライアント・コードに対して、その状態を保護するためにXオブジェクト自体を使用するロックを使用して、このクライアント・コードを保護することです.クライアント・ロックを使用するには、オブジェクトXがどのロックを使用しているかを知る必要があります.
4.4.2組合せ
既存のクラスに原子操作を追加する場合、【組合せ】
プログラムリスト4-16は、組合せによって実現される「なければ追加する」
プログラムリスト4-1 Javaモニタモードを使用したスレッドセキュリティカウンタ
@ThreadSafe
public final class Counter {
@GuardedBy("this")private long value = 0;
public synchronized long getValue() {
return value;
}
public synchronized long increment() {
if(value == Long.MAX_VALUE)
throw new IllegalStateException("counter overflow");
return ++value;
}
}
4.2インスタンス閉鎖
プログラムリスト4-2閉鎖機構によりスレッドの安全を確保
/**
1.PersonSet HashSet , HashSet 。
2. mySet , HashSet PersonSet 。
3. addPerson containsPerson , PersonSet
4. PersonSet ,
*/
@ThreadSafe
public class PersonSet {
private final Set mySet = new HashSet<>();
public synchronized void addPerson(Person p) {
mySet.add(p);
}
public synchronized boolean containsPerson(Person p) {
return mySet.contains(p);
}
}
4.2.1 Javaモニタモード
Java , 。eg: Vector,HashTable。
Java , , 。
プログラムリスト4-3は、プライベートロックによって状態を保護する
プライベートロックオブジェクトは、クライアントコードを使用してロックを取得できないロックをカプセル化できますが、publicメソッドでロックにアクセスして同期ポリシーに参加することができます.
public class PrivateLock {
private final Object myLock = new Object();
Widget widget;
void someMethod() {
synchronized (myLock) {
// widget
}
}
}
4.2.2例:車両追跡器
プログラムリスト4-4モニタモードによる車両追跡
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;
import lombok.experimental.Accessors;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.NotThreadSafe;
import net.jcip.annotations.ThreadSafe;
/**
MutablePoint ,
Map Point 。
, copy ,
*/
@ThreadSafe
public class MonitorVehicleTracker { //vehicle [ˈvi:əkl] n. ; ;
@GuardedBy("this")
private final Map locations;
public MonitorVehicleTracker(Map locations) {
this.locations = locations;
}
//
public synchronized Map getLocations(){
return deepCopy(locations);
}
// id
public synchronized MutablePoint getLocation(String id){
MutablePoint loc = locations.get(id);
return loc == null ? null : new MutablePoint(loc);
}
// id
public synchronized void setLocation(String id,int x, int y){
MutablePoint loc = locations.get(id);
if(loc == null)
throw new IllegalArgumentException("no such ID : " + id);
loc.setX(x).setY(y);
}
//
private static Map deepCopy(Map m) {
Map result = new HashMap<>(); //
m.keySet().forEach(id->result.put(id, new MutablePoint(m.get(id))));//
return Collections.unmodifiableMap(result);// map
}
}
// 4-5 Java.awt.Point Point ( )
/**
*/
@Data
@NotThreadSafe
@Accessors(chain = true)
class MutablePoint{ //mutable [ˈmju:təbl] adj. , ;
private int x;
private int y;
public MutablePoint(MutablePoint mutalbePoint) {
this.x = mutalbePoint.getX();
this.y = mutalbePoint.getY();
}
}
4.3スレッドセキュリティの依頼
4.3.1委託による車両トラッカー
プログラムリスト4-7スレッドセキュリティをConcurrentHashMapに委任
/**
* , ConcurrentMap , map
* ConcurrentMap key final
*
* Point , 。 , location 。
*
* 1、2 :
* A 【getLocations】 B 【setLocation】 ,
* A Map
* :
* :
*
*/
@ThreadSafe
public class DelegatingVehicleTracker {
private final ConcurrentMap locations;
private final Map unmodifiableMap;
public DelegatingVehicleTracker(Map points) {
locations = new ConcurrentHashMap<>(points);
unmodifiableMap = Collections.unmodifiableMap(points);
}
//1、
public Map getLocations() {
// return Collections.unmodifiableMap(new HashMap(locations)); // locations
return unmodifiableMap; //
}
//2、
public Point getLocation(String id) {
return locations.get(id);
}
public void setLocation(String id, int x, int y) {
if(locations.replace(id, new Point(x,y)) == null)
throw new IllegalArgumentException("invalid vehicle name : ");
}
}
4.3.2独立した状態変数
プログラムリスト4-9スレッドセキュリティを複数のステータス変数に委任
/**
* keyListeners,mouseListeners ,
* VisualComponent keyListeners mouseListeners
*/
public class VisualComponent {
//CopyOnWriteArrayList ,
private final List keyListeners = new CopyOnWriteArrayList<>();
private final List mouseListeners = new CopyOnWriteArrayList<>();
public void addKeyListener(KeyListener listener) {
keyListeners.add(listener);
}
public void addMouseListener(MouseListener mouseListener) {
mouseListeners.add(mouseListener);
}
public void removeKeyListener(KeyListener keyListener) {
keyListeners.remove(keyListener);
}
public void removeMouseListener(MouseListener mouseListener) {
mouseListeners.remove(mouseListener);
}
}
4.3.3委託が失効した場合
プログラムリスト4-10 NumberRangeクラスはその不変性条件を保護するのに十分ではありません(そうしないでください)
/**
* : (0,10), setLower(5), setUpper(4),
* : , , 。
* : (5,4),
* : AtomicInteger , 。
* :lower upper ,
* :NumberRange 。
*/
import java.util.concurrent.atomic.AtomicInteger;
public class NumberRange {
// lower < upper
private final AtomicInteger lower = new AtomicInteger(0);
private final AtomicInteger upper = new AtomicInteger(0);
public void setLower(int i) {
// : “ ”
if(i > upper.get())
throw new IllegalArgumentException("cant't set lower to " + i + " > upper");
lower.set(i);
}
public void setUpper(int i) {
// : “ ”
if(i < lower.get())
throw new IllegalArgumentException("cant't set lower to " + i + " < lower");
lower.set(i);
}
public boolean isInRange(int i) {
return (i >= lower.get() && i <= upper.get());
}
}
4.3.5例:発行状態の車両追跡器
プログラムリスト4-11スレッドが安全で可変なPointクラス
/**
* 【 】
* ,
* ?
*
*/
@ThreadSafe
public class SafePoint {
private int x,y;
public SafePoint(int x, int y) {
this.x = x;
this.y = y;
}
private SafePoint(int[] a) { this(a[0],a[1]); }
/* this.(p.x,p.y), , public
* private
*/
public SafePoint(SafePoint p) { this(p.get()); }
/*
* x y get , 2 ,
* x,y , : (x,y)。
*
* SafePoint, ,
* 。
*/
public synchronized int[] get() {
return new int[] {x,y};
}
public synchronized void set(int x,int y) {
this.x = x;
this.y = y;
}
}
プログラムリスト4-12最下位状態の車両追跡器を安全に公開する
/**
* 4-7 :
* 1、
* 4-7: Point:
* 4-12:SafePoint:
* 2.
* 4-7:setLocation() replace()
* 4-12:setLocation() containKey()
*/
@ThreadSafe
public class PublishingVehicleTracker {
private final Map locations;
private final Map unmodifyMap;
public PublishingVehicleTracker(Map locations) {
this.locations = new ConcurrentHashMap(locations);
this.unmodifyMap = Collections.unmodifiableMap(this.locations);
}
public Map getLocations() {
return unmodifyMap;
}
public SafePoint getLocation(String id) {
return locations.get(id);
}
public void setLocation(String id,int x, int y) {
if(!locations.containsKey(id))
throw new IllegalArgumentException("invalid vehicle name: " + id);
locations.get(id).set(x, y);
}
}
4.4既存のスレッドセキュリティクラスに機能を追加する
プログラムリスト4-13は、Vectorを拡張し、「なければ追加」メソッドを追加します.
// Vector ,
public class BetterVector extends Vector {
/**
* absent [ˈæbsənt]
* adj. , ; , ; , ;
* vt. , ; ;
*/
public synchronized boolean putIfAbsent(E x) {
boolean absent = !contains(x);
if(absent)
add(x);
return absent;
}
}
4.4.1クライアントロックメカニズム
プログラムリスト4-14非スレッドセキュリティの「なければ追加」(そうしない)
/**
* 【 】
* synchronized
* Collections.synchronizedList(List list) :
* Collectons.SynchronizedCollection.mutex (final)
* putIfAbsent List
*/
@NotThreadSafe
public class ListHelper {
public List list = Collections.synchronizedList(new ArrayList());
/**
* absent [ˈæbsənt]
* adj. , ; , ; , ;
* vt. , ; ;
*/
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
}
プログラムリスト4-15は、クライアントのロックによって実現される「なければ追加する」
クライアント・ロックとは、オブジェクトXを使用するクライアント・コードに対して、その状態を保護するためにXオブジェクト自体を使用するロックを使用して、このクライアント・コードを保護することです.クライアント・ロックを使用するには、オブジェクトXがどのロックを使用しているかを知る必要があります.
/**
* (BetterVector), ,
* , ,
* ( list) ,
*/
@ThreadSafe
public class ListHelper {
public List list = Collections.synchronizedList(new ArrayList());
public boolean putIfAbsent(E x) {
synchronized (list) { // list , list ,
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
}
}
4.4.2組合せ
既存のクラスに原子操作を追加する場合、【組合せ】
プログラムリスト4-16は、組合せによって実現される「なければ追加する」
/**
* ImprovedList 。
* List , List ,
* ImprovedList 。
* , ,【ImprovedList 】。
* , Java List, List , 。
*/
public class ImprovedList implements List {
private final List list;
public ImprovedList(List list) {
this.list = list;
}
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
@Override
public synchronized void clear() {
list.clear();
}
//...... List
}