美文网首页
【java并发编程实战】第二章笔记:对象的共享

【java并发编程实战】第二章笔记:对象的共享

作者: 吃海苔的我 | 来源:发表于2018-08-27 14:07 被阅读0次

    1.重要的属性

    可见性,不变性,原子性

    1.1可见性

    当一个线程修改某个对象状态的时候,我们希望其他线程也能看到发生后的变化。

    在没有同步的情况下,编译器和处理器会对代码的执行顺序进行重排。以提高效率。重排后的顺序是不可预知的,所以在多线程中无法对执行结果进行判断
    看下面的代码

    public class NoVisibility {
    
        private static boolean ready;
    
        private static int number;
    
        private static class ReaderThread extends Thread {
            @Override
            public void run() {
                while (!ready) {
                    System.out.println(">>>");
                }
                System.out.println(1/number);
            }
        }
    
        public static void main(String[] args) {
            new ReaderThread().start();
    
            number = 1;
    
            ready = true;
        }
    
    }
    

    上面的执行结果可能会一直执行下去,也可能抛错。我们期望number=1以后,ready=true执行,最后输出1/1=1,由于重排,可能导致ready先初始化,然后线程读取到的还是ready=true,number=0.导致异常.


    最低安全性:线程在没有同步的情况下可能会得到失效的值,但是至少这个值是之前某个线程设置的,而不是随机值。但有一个例外,看下面
    其中提到了一个很有趣的非原子的64位操作
    jvm内存模型规定,变量的读写操作都要原子性,但是有个例外,非volatile修饰的long和double这64位的操作,jvm允许将64位的读写操作分成2个32位的操作,就可能导致读取到的某个值的高32位和另外一个值的低32位。
    除非用volatile或者锁保护起来


    1.1.1 volatile

    基础
    1.弱同步机制,volatile更新后的值将会通知其他线程。
    2.变量修饰后,jvm或处理器不会对其进行指令重排。
    3.不会被缓存在寄存器或者其他处理器看不到的地方。所以读取的值都是最新的。
    其中与加锁不同的是,加锁可以保证原子性和可见性,但是volatile修饰后只能保证可见性。

    1.1.2 threadlocal

    threadlocal是为了防止可变的单实例变量或全局变量进行共享。jdbc就是采用了threadlocal。

    threadlocal这里只描述场景和并发的关系。需要独立篇幅进行原理分析。

    1.1.3

    解决并发问题的另一个解决方案,不变形对象。不可变对象一定是线程安全的。

    对象不可变的满足条件:

    ①对象创建后就不可修改
    ②对象的所有域都是final修饰
    ③对象是正确创建的,创建期间没有this溢出被其他地方修改。

    final修饰的List,Map等都是可以继续添加元素。可以采用Collections.unmodifiableXXX()。其实它的原理不过是实现一个Map接口。重写了put和remove等修改的时候进行异常抛出的操作。

        private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
            private static final long serialVersionUID = -1034234728574286014L;
    
            private final Map<? extends K, ? extends V> m;
    
            UnmodifiableMap(Map<? extends K, ? extends V> m) {
                if (m==null)
                    throw new NullPointerException();
                this.m = m;
            }
    
            // 省略
    
            public V put(K key, V value) {
                throw new UnsupportedOperationException();
            }
            public V remove(Object key) {
                throw new UnsupportedOperationException();
            }
            public void putAll(Map<? extends K, ? extends V> m) {
                throw new UnsupportedOperationException();
            }
        }
    

    相关文章

      网友评论

          本文标题:【java并发编程实战】第二章笔记:对象的共享

          本文链接:https://www.haomeiwen.com/subject/uvdmiftx.html