《java并发编程实战》-(2)-线程安全性-(不可变对象)

2018-09-03  本文已影响34人  小超人爱小土豆

我们在满足同步需求的一种重要手段就是使用不可变对象,之前出现线程不安全的情况都是与多线程试图同时访问一个可变的状态相关。如果对象的状态不会改变,那么这些问题与复杂性就会自然消失了。

【注意】不可变对象一定是线程安全的!!!

1.概念

1.1不可变对象

有一种对象只要它发布了就是线程安全的,他就是不可变对象,一个不可变对象需要满足的条件是:

1.2创建一个不可变对象的方法

(1)自定义
这里可以才去的方式包括:

(2)使用Java中提供的Collection类中的各种unmodifiable开头的方法 。
(3)使用Guava中的Immutable开头的类。

2.Final关键字

inal关键字可以修饰类、修饰方法、修饰变量

【注意】
(1)对一个被final修饰的变量(Integer a、String b)被赋值时在编译过程中就出现了错误。
(2)(map)在重新被指向一个新的map对象的时候也会出现错误。
(3) 被final修饰的引用类型变量,虽然不能重新指向,但是可以修改,这一点尤为要注意。
(4)当final修饰方法的参数时:同样也是不允许在方法内部对其修改的。

【面试常考】 final、finally、finalize的区别

3.Java unmodifiable相关方法

使用Java的Collection类的unmodifiable相关方法,可以创建不可变对象。unmodifiable相关方法包含:Collection、List、Map、Set等。 Collection类的unmodifiable相关方法

eg:


    private static Map<Integer, Integer> map = Maps.newHashMap();

    static {
        map.put(1, 2);
        map.put(3, 4);
        map.put(5, 6);
        map = Collections.unmodifiableMap(map);
    }

    public static void main(String[] args) {
        map.put(1, 3);
        log.info("{}", map.get(1));
    }

}

上面程序的执行结果为:在map.put(1,3)操作的位置抛出了异常。由此可见map对象已经成为不可变对象。

Collections.unmodifiableMap在执行时,将参数中的map对象进行了转换,转换为Collection类中的内部类 UnmodifiableMap对象。而 UnmodifiableMap对map的更新方法(比如put、remove等)进行了重写,均返回UnsupportedOperationException异常,这样就做到了map对象的不可变。

        return new UnmodifiableMap<>(m);
}
private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
    ...
    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }
    ...
}

未完待续 - - -

上一篇 下一篇

猜你喜欢

热点阅读