《java并发编程实战》第三章

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013276277/article/details/81060010

不变性

         满足同步需求的另一种方法是使用不可变对象。目前为止遇到的多线程并发问题,例如失效数据,丢失更新或者某一对象的状态不一致,这些问题的根源在于操作对象状态的可变性。如果某一个对象在被创建后其状态不能被修改,那么这个对象就被称为不可变对象。

记住,不可变对象一定是线程安全的。不可变对象的设计很简单,他们只有一种状态,并且该状态是由构造函数来控制的。

Final域

         在java内存模型中,final域还有特殊的语义,final域能确保初始化过程中的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无需同步。

这边摘自《java并发编程实战》的一段话:

“除非需要更高的可见性,否则应将所有的域都声明为私有域”——良好的编程习惯

“除非需要某个域是可变的,否则影将其声明为final域”——良好的变成习惯

使用volatile类型来发布不可变对象

在某些情况下,不可变对象能提供一种弱形式的原子性。

package com.zy.charter3;

import java.math.BigInteger;
import java.util.Arrays;

class OneValueCache {// 不可变对象
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;
    
    public OneValueCache(BigInteger lastNumber, BigInteger[] lastFactors) {
        this.lastNumber = lastNumber;
        this.lastFactors = lastFactors;
    }
    
    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i)) {
            return null;
        } else {
            return Arrays.copyOf(lastFactors, lastFactors.length);
        }
    }
    
} 

public class VolatileCachedFactorizer {
    private volatile OneValueCache cache = new OneValueCache(null, null);// 保证可见性
    
    public void service(BigInteger i) {
        BigInteger[] factors = cache.getFactors(i);
        if (factors == null) {
            factors = new BigInteger[4];
            cache = new OneValueCache(i, factors);
        }
    }
}



在并发编程中使用和共享对象时,可以使用一些实用的策略,包括:
    线程封闭:线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个县城修改。

    只读共享:在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它,共享的只读对象包括不可变对象和事实不可变对象。

    线程安全共享:线程安全的对象在其内部实现同步,因此多个线程可以通过对象的公有接口来进行访问而不需要进一步的同步。

    保护对象:被保护的对象只能通过持有特定的锁来访问,保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且由某个特定锁保护的对象。(不明白这句话的意思)



猜你喜欢

转载自blog.csdn.net/u013276277/article/details/81060010