# introduce

线程安全问题主要是由于多个线程对共享资源同时进行访问而出现的,解决该问题通常使用的 synchronized 锁定共享资源,使得共享资源每次只能由一个线程进行操作。

除了上述的方式之外,还可以通过将共享资源设置为不可变的状态,使得多个线程同时访问也不会对其产生变化,达到线程安全的目的,同时由于不再使用 synchroinzed 可以节省资源提高性能。

不可变对象最核心的地方在于不给外部修改共享资源的机会,这样就会避免多线程情况下的数据冲突导致的不一致的情况,又能避免因为对锁的依赖而带来的性能降低。

# 实现

实现一个累加器

# 线程不安全的累加器

# 代码如下

/**
 * <p> 线程不安全的 int 类型累加器 </p>
 *
 * @Author 彳失口亍
 */
public class UnSafeIntegerAccumulator {
    /** 值 **/
    @Getter
    private int value;

    /** 构造函数,并制定初始值 **/
    public UnSafeIntegerAccumulator(int init) {
        this.value = init;
    }

    /** 进行累加操作 **/
    public int add(int i){
        this.value += i;
        return this.value;
    }
}

# 演示,线程问题

# 通过加 synchronized 解决线程安全问题

# 线程安全的累加器(不可变对象设计模式)

# 代码如下

/**
 * <p> 线程安全的 int 类型累加器(不可变对象设计模式) </p>
 *
 * class final 类不允许被继承
 *
 * @Author 彳失口亍
 */
public final class SafeIntegerAccumulator {
    /** 值 **/
    @Getter
    private final int value;

    /** 构造函数,并制定初始值 **/
    public SafeIntegerAccumulator(int init) {
        this.value = init;
    }

    /** 构造新的累加器 **/
    public SafeIntegerAccumulator(SafeIntegerAccumulator accumulator,int init){
        this.value = accumulator.getValue() + init;
    }

    /** 进行累加操作 **/
    public SafeIntegerAccumulator add(int i){
        return new SafeIntegerAccumulator(this,i);
    }
}

不可变对象能够达到不加锁也能实现线程安全的原因:

  • 1、class 增加 final,防止被继承重写导致失去线程安全性
  • 2、属性 value 被 final 修饰,不允许线程对其进行改变,在构造函数赋值后,无法再进行修改。

# 演示

精彩内容推送,请关注公众号!
最近更新时间: 5/14/2020, 12:49:41 PM