zoukankan      html  css  js  c++  java
  • java多线程补:充原子性和可见性

    参考:http://www.cnblogs.com/mengyan/archive/2012/08/22/2651575.html

    原子性:所谓原子性就是不可分割的,比如:在我们编程中直接给变量赋值,这就是不可分割的,就具有原子性,相对的,非原子性就是在编程中步骤被分割的,比如编程中的计算,是分步骤进行的,例如:a+=b,其实编程是分为三步,1、先取出a和b的值 2、计算a+b 3、写入内存。这就是非原子性。

    可见性:提到可见性,很多同学就会想到一个关键字 volatile ,没错,在多线程中,解决变量的可见性就是利用了volatile这个修饰词。

    多线程变量不可见:当一个线程对一变量a修改后,还没有来得及将修改后的a值回写到主存,而被线程调度器中断操作(或收回时间片),然后让另一线程进行对a变量的访问修改,这时候,后来的线程并不知道a值已经修改过,它使用的仍旧是修改之前的a值,这样修改后的a值就被另一线程覆盖掉了。

    多线程变量可见:被volatile修饰的成员变量在每次被线程访问时,都强迫从内存中重读该成员变量的值;而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存,这样在任何时刻两个不同线程总是看到某一成员变量的同一个值,这就是保证了可见性。

    举个例子:

    编写一个线程类:

    public class MyThread4 implements Runnable {
        private boolean isRun = true;
    
        public boolean isRun() {
            return isRun;
        }
    
        public void setRun(boolean run) {
            isRun = run;
        }
    
        @Override
        public void run() {
            System.out.println("4开始运行了");
            while (isRun){
               
            }
        }
    }

    main()方法运行

    MyThread4 myThread4 = new MyThread4();
            Thread thread = new Thread(myThread4);
            thread.start();
            try {
                Thread.sleep(100);
                myThread4.setRun(false);
                System.out.println("停了吗");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    看运行结果,会发现线程进入了死循环,myThread4.setRun(false);这行代码并没有使线程重新拿到 isRun 的赋值,这说明线程之间对同一个变量的操作是不可见的。

    当我们把 isRun 加上volatile关键字时如下:

    public class MyThread4 implements Runnable {
        private volatile boolean isRun = true;
    
        public boolean isRun() {
            return isRun;
        }
    
        public void setRun(boolean run) {
            isRun = run;
        }
    
        @Override
        public void run() {
            System.out.println("4开始运行了");
            while (isRun){
                
            }
        }
    }

    再次运行我们会发现,代码不会进入死循环,由此可见,关键字volatile 保障了线程之间变量的可见性。

    拓展:当我们在while循环中加入有synchronized关键字修饰的方法时,比如System.out.println();这时代码也不会陷入死循环,因此synchronized除了保障了原子性外,其实也保障了可见性。因为synchronized无论是同步的方法还是同步的代码块,都会先把主内存的数据拷贝到工作内存中,同步代码块结束,会把工作内存中的数据更新到主内存中,这样主内存中的数据一定是最新的。

  • 相关阅读:
    tsql导出EXCEL语句待测试
    IE和Firefox下event乱谈
    cf 167.d( 多重集全排列 )
    poj 1815(最小割 + 枚举)
    Codeforces Round #167 (Div. 2)
    poj 3308(最小割+对数处理)
    在FootTemplate与ItemTemplate中间扩展Repeater模板
    在没有高度设定的情况下让margintop生效
    float:left后整体居中
    判断ExecuteScalar()是否返回结果
  • 原文地址:https://www.cnblogs.com/bestxyl/p/8779970.html
Copyright © 2011-2022 走看看