JAVA并发编程实战笔记03

1.怎么设计线程安全的类?

  a.找出构成对象状态的所有变量

  b.找出约束状态变量的不变性条件

  c.建立对象状态的并发访问管理策略

   对于b点大家肯定有疑惑怎么找出状态变量不变性条件,举个例子假如设计一个一天的时间点,时间只能是24个小时,60分钟,60秒,三个变量这是它不变性条件,找出不变性的目的是收集同步需求,保证不变性不会再并发情况下不被破坏,还有一个点必须提一下,先验性(空对象不能获取它的属性,肯定要先判断它是否为空),也可以叫依赖状态的操作,要保证不变性条件。

  c点大家可以参考JAVA并发秉承实战笔记02

2.JAVA监视器模式:遵循JAVA监视器模式的对象会把对象的所有可变状态都封装起来,并由对象自己的内置锁来保护

public class PrivateLock {
    private final Object myLock = new Object();
    @GuardedBy("myLock") Widget widget;

    void someMethod() {
        synchronized (myLock) {
            // Access or modify the state of widget
        }
    }
}

3.对象的组合

1.使用并发容器类来实现对象组合的线程安全比如:ConcurrentMap,CopyOnWriteArrayList、CopyOnWriteLinkList

2.使用JAVA监视器模式

注:如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都包含无效状态的装换,那么可以将线程安全线委托给底层的状态变量,此类不是线程安全的

public class NumberRange {
    // INVARIANT: lower <= upper
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);

    public void setLower(int i) {
        // Warning -- unsafe check-then-act
        if (i > upper.get())
            throw new IllegalArgumentException("can't set lower to " + i + " > upper");
        lower.set(i);
    }

    public void setUpper(int i) {
        // Warning -- unsafe check-then-act
        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());
    }
}

NumberRange线程安全性人物给“AtomicInteger”,不变性条件: lower <= upper,上述例子即使 lower ,upper是线程安全的,但是两个变量存在不变性条件,所以NumberRange不是线程安全的。

4.加锁机制(不使用同一把锁导致线程不安全)

@NotThreadSafe
class BadListHelper <E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());

    public synchronized boolean putIfAbsent(E x) {
        boolean absent = !list.contains(x);
        if (absent)
            list.add(x);
        return absent;
    }
}

修复完的代码

@ThreadSafe
class GoodListHelper <E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());

    public boolean putIfAbsent(E x) {
        synchronized (list) {
            boolean absent = !list.contains(x);
            if (absent)
                list.add(x);
            return absent;
        }
    }
}

当锁发生变化时,导致线程不安全

public class ChangeLock {
	private String lock = "lock";
	private void method(){
		synchronized (lock) {
			try {
				System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
				lock = "change lock";
				Thread.sleep(2000);
				System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
	
		final ChangeLock changeLock = new ChangeLock();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				changeLock.method();
			}
		},"t1");
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				changeLock.method();
			}
		},"t2");
		t1.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}
	
}
在现有的线程安全类扩展功能方式:继承、组合

@ThreadSafe
public class BetterVector <E> extends Vector<E> {
    // When extending a serializable class, you should redefine serialVersionUID
    static final long serialVersionUID = -3963416950630760754L;

    public synchronized boolean putIfAbsent(E x) {
        boolean absent = !contains(x);
        if (absent)
            add(x);
        return absent;
    }
}


@ThreadSafe
public class ImprovedList<T> implements List<T> {
    private final List<T> list;

    /**
     * PRE: list argument is thread-safe.
     */
    public ImprovedList(List<T> list) { this.list = list; }

    public synchronized boolean putIfAbsent(T x) {
        boolean contains = list.contains(x);
        if (contains)
            list.add(x);
        return !contains;
    }
    //...
}
将同步策略文档化,有相应的文档做说明



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值