Board logo

标题: java 内存模型-02-数据结构(6) [打印本页]

作者: look_w    时间: 2019-3-11 20:22     标题: java 内存模型-02-数据结构(6)

并发特征

Java内存模型是围绕着并发编程中原子性、可见性、有序性这三个特征来建立的。
原子性(Atomicity)

一个操作不能被打断,要么全部执行完毕,要么不执行。在这点上有点类似于事务操作,要么全部执行成功,要么回退到执行该操作之前的状态。

基本类型数据的访问大都是原子操作,long 和 double 类型的变量是64位,但是在32位JVM中,32位的JVM会将64位数据的读写操作分为2次32位的读写操作来进行,这就导致了long、double 类型的变量在32位虚拟机中是非原子操作,数据有可能会被破坏,也就意味着多个线程在并发访问的时候是线程非安全的。

下面我们来演示这个32位JVM下,对64位long类型的数据的访问的问题:

    public class NotAtomicity {
        //静态变量t
        public  static long t = 0;
        //静态变量t的get方法
        public  static long getT() {
            return t;
        }
        //静态变量t的set方法
        public  static void setT(long t) {
            NotAtomicity.t = t;
        }
        //改变变量t的线程
        public static class ChangeT implements Runnable{
            private long to;
            public ChangeT(long to) {
                this.to = to;
            }
            public void run() {
                //不断的将long变量设值到 t中
                while (true) {
                    NotAtomicity.setT(to);
                    //将当前线程的执行时间片段让出去,以便由线程调度机制重新决定哪个线程可以执行
                    Thread.yield();
                }
            }
        }
        //读取变量t的线程,若读取的值和设置的值不一致,说明变量t的数据被破坏了,即线程不安全
        public static class ReadT implements Runnable{
     
            public void run() {
                //不断的读取NotAtomicity的t的值
                while (true) {
                    long tmp = NotAtomicity.getT();
                    //比较是否是自己设值的其中一个
                    if (tmp != 100L && tmp != 200L && tmp != -300L && tmp != -400L) {
                        //程序若执行到这里,说明long类型变量t,其数据已经被破坏了
                        System.out.println(tmp);
                    }
                    ////将当前线程的执行时间片段让出去,以便由线程调度机制重新决定哪个线程可以执行
                    Thread.yield();
                }
            }
        }
        public static void main(String[] args) {
            new Thread(new ChangeT(100L)).start();
            new Thread(new ChangeT(200L)).start();
            new Thread(new ChangeT(-300L)).start();
            new Thread(new ChangeT(-400L)).start();
            new Thread(new ReadT()).start();
        }
    }

我们创建了4个线程来对long类型的变量t进行赋值,赋值分别为100,200,-300,-400,有一个线程负责读取变量t,如果正常的话,读取到的t的值应该是我们赋值中的一个,但是在32的JVM中,事情会出乎预料。如果程序正常的话,我们控制台不会有任何的输出,可实际上,程序一运行,控制台就输出了下面的信息:

    -4294967096
    4294966896
    -4294967096
    -4294967096
    4294966896

之所以会出现上面的情况,是因为在32位JVM中,64位的long数据的读和写都不是原子操作,即不具有原子性,并发的时候相互干扰了。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0