学习书籍《Java concurrency in practice》
设计线程安全类,三个基本要素:
找出构成对象状态的所有变量
找出约束状态变量的不变性条件
简历对象状态的并发访问管理策略
1.使用java监视器模式(也就是synchronized模式)的线程安全计数器
public class Counter {
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;
}
}
2.通过封闭机制来确保线程安全
import java.util.HashSet;
import java.util.Set;
public class PersonSet {
private final Set set = new HashSet<>();
public synchronized PersonSet addString(String string){
set.add(string);
return this;
}
public synchronized boolean containsString(String string){
return set.contains(string);
}
}
3.通过一个私有锁来保护状态
public class PrivateLock {
private final Object myLock = new Object();
Object widget;
void someMethod(){
synchronized(myLock){
//修改widget的状态
}
}
}
4.基于监视器模式的车辆追踪
MultablePoint用来表示车辆坐标,这个类线程不安全
class MultablePoint{
int x;
int y;
public MultablePoint() {
set(0,0);
}
public MultablePoint(MultablePoint p) {
set(p.x,p.y);
}
public MultablePoint(int x,int y) {
set(x,y);
}
public MultablePoint set(int x, int y) {
this.x = x;
this.y = y;
return this;
}
}
尽管MutablePoint线程不安全,但是追踪器类是线程安全的,它所包含的Map对象和可变的Point对象都未曾发布.当需要返回车辆的位置时,通过MutablePoint拷贝或者deepCopy方法类复制正确的值,从而生成一个新的Map对象.
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MonitorVehicleTracker {
private Map locations;
public MonitorVehicleTracker(HashMap locations) {
this.locations = deepCopy(locations);
}
public synchronized void setLocation(String id,int x,int y) {
locations.compute(id, (k,v)->v==null?new MultablePoint(x,y):v.set(x,y));
}
public synchronized Map getLocations() {
return deepCopy(locations);
}
public synchronized MultablePoint getLocation(String id){
MultablePoint mPoint = locations.get(id);
return mPoint==null?null:new MultablePoint(mPoint);
}
private static Map deepCopy(Map locations) {
final HashMap map = new HashMap();
locations.forEach((k,v)->map.put(k, new MultablePoint(v)));
return Collections.unmodifiableMap(map);
}
}
5.基于委托的车辆追踪器
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class DelegatingVehicleTracker {
private final ConcurrentMap locations;
private final Map unmodifiableMap;
public DelegatingVehicleTracker(Map points) {
locations = new ConcurrentHashMap(points);
unmodifiableMap = Collections.unmodifiableMap(locations);
}
//实时拷贝
public Map getLocations(){
return unmodifiableMap;
}
/*静态拷贝
* public Map getLocations(){
* return Collections.unmodifiableMap(
* new HashMap(locations));
*}
*/
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: "+id);
}
}
}
class Point{
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
6.将线程安全性委托给多个状态变量
前提条件: 这些多个状态变量之间是相互独立的
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class VisualComponent {
private final List keyListeners = new CopyOnWriteArrayList<>();
private final List mouseListeners = new CopyOnWriteArrayList<>();
public void addKeyListener(KeyListener listener){
keyListeners.add(listener);
}
public void addMouseListener(MouseListener listener){
mouseListeners.add(listener);
}
public boolean removeKeyListener(KeyListener listener){
return keyListeners.remove(listener);
}
public boolean removeMouseListener(MouseListener listener){
return mouseListeners.remove(listener);
}
}
class KeyListener{
}
class MouseListener{
}
7.多个变量存在耦合关系,使用委托机制(非常糟糕的设计)
import java.util.concurrent.atomic.AtomicInteger;
public class NumberRange {
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("can't set lower to "+i+" > upper");
}
lower.set(i);
}
public void setUpper(int i){
//不安全的"先检查后执行"
if(i < lower.get()){
throw new IllegalArgumentException("can't set upper to "+i+" < lower");
}
upper.set(i);
}
public boolean isInRange(int i){
return i >= lower.get() && i <=upper.get();
}
}
将NumberRanger设置为线程安全的类的话,就需要使用一个锁来保护lower和upper,此外还必须避免发布lower和upper,从而防止客户端代码破坏其不变性.
8.安全发布底层状态的车辆追踪器:
1) 线程安全且可变的SafePoint类:
class SafePoint{
private int x;
private int y;
public SafePoint(int x, int y) {
set(x,y);
}
public synchronized int[] get(){
return new int []{x,y};
}
public synchronized SafePoint set(int x,int y){
this.x = x;
this.y = y;
return this;
}
}
2) 安全发布底层状态的车辆追踪器
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class PublishingVechicleTracker {
private final Map locations;
private final Map unmodifiableMap;
public PublishingVechicleTracker(Map locations){
this.locations = new ConcurrentHashMap();
this.unmodifiableMap = Collections.unmodifiableMap(this.locations);
}
public Map getLocations(){
return unmodifiableMap;
}
public SafePoint getLocation(String id){
return locations.get(id);
}
public void setLocation(String id,int x,int y){
locations.compute(id, (k,v)->{
if(v==null)
throw new IllegalArgumentException("invalid vehicle name: "+id);
return v.set(x, y);
});
}
}
PublishingVehicleTracker将其线程安全性委托给底层的ConcurrentHashMap,只是Map的元素是线程安全的且可变的Point,并非不可改变的.
9.客户端加锁机制
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListHelper <E>{
private final List list = Collections.synchronizedList(new ArrayList());
/*//不安全的操作
public synchronized boolean putIfAbsent(E x){
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
*/
//通过客户端锁来实现
public boolean putIfAbsent(E x){
synchronized (list) {
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
}
}
10.为现有类添加一个原子操作,比较好的办法是: 组合
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ImprovedList implements List {
private final List list;
public ImprovedList(List list){
this.list = list;
}
//添加一个原子操作putIfAbsent
public synchronized boolean putIfAbsent(T x){
boolean absent = !list.contains(x);
if(absent)
list.add(x);
return absent;
}
@Override
public synchronized int size() {
return list.size();
}
@Override
public synchronized boolean isEmpty() {
return list.isEmpty();
}
@Override
public synchronized boolean contains(Object o) {
return list.contains(o);
}
@Override
public synchronized Iterator iterator() {
return list.iterator();
}
@Override
public synchronized Object[] toArray() {
return list.toArray();
}
@SuppressWarnings("hiding")
@Override
public synchronized T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public synchronized boolean add(T e) {
return list.add(e);
}
@Override
public synchronized boolean remove(Object o) {
return list.remove(o);
}
@Override
public synchronized boolean containsAll(Collection> c) {
return list.containsAll(c);
}
@Override
public synchronized boolean addAll(Collection extends T> c) {
return list.addAll(c);
}
@Override
public synchronized boolean addAll(int index, Collection extends T> c) {
return list.addAll(c);
}
@Override
public synchronized boolean removeAll(Collection> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection> c) {
return list.retainAll(c);
}
@Override
public synchronized void clear() {
list.clear();
}
@Override
public synchronized T get(int index) {
return list.get(index);
}
@Override
public synchronized T set(int index, T element) {
return list.set(index, element);
}
@Override
public synchronized void add(int index, T element) {
list.add(index, element);
}
@Override
public synchronized T remove(int index) {
return list.remove(index);
}
@Override
public synchronized int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public synchronized int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public synchronized ListIterator listIterator() {
return list.listIterator();
}
@Override
public synchronized ListIterator listIterator(int index) {
return list.listIterator(index);
}
@Override
public synchronized List subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
}