java多线程(五) 之 设计线程安全的类

学习书籍《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 c) {
        return list.addAll(c);
    }

    @Override
    public synchronized boolean addAll(int index, Collection 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);
    }

}

你可能感兴趣的:(java多线程)