zoukankan      html  css  js  c++  java
  • 局部变量的可见性

    1 问题的引出

    局部变量跨线程,又不能用volatile,怎么保证其可见性

    2 是否真的能有局部变量跨线程写入?

    看一下这段代码:

        public static void main(String []f) {
            Integer integer = 1;
            new Thread(new InnerThread(integer)).start();
            while(true) {
                if(integer == 2) break;
            }
        }
    
        private static class InnerThread implements Runnable {
            private Integer innerInteger;
    
            public InnerThread(Integer integer) {
                this.innerInteger = integer;
            }
    
            @Override
            public void run() {
                innerInteger = 2;
            }
        }
    

      

     这个代码有没有可见性问题?答案是没有的

    两条线程访问的其实是2个变量,是没有线程并发可见性问题的,因为java不像c++那样有变量的引用语法,&integer,子线程的构造其实是c++里面的值传递而不是引用传递,什么叫值传递?引用传递?

        public static void main(String []f) {
            Integer x = 1;
            setInt(x);
            System.out.println(x);
    
        }
    
        private static void setInt(Integer x) {
            x = 2;
        }
    
    打印1,值传递,打印2,引用传递
    

      

    子线程写入的是线程内部的局部对象,主线程读取的是main方法的局部对象,根本是2个变量,自然无可见性问题

    3 那么有没有使用一个局部对象的多线程写入?答案是有的

        public static void main(String []f) {
            Integer integer = 1;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    integer = 2;
                }
            }).start();
            while(true) {
                if(integer == 2) break;
            }
        }
    

      

    然而,这个代码是过不了编译的,必须在integer上加上final

        public static void main(String []f) {
            final Integer integer = 1;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    integer = 2;
                }
            }).start();
            while(true) {
                if(integer == 2) break;
            }
        }
    

      

    然而加上final后,integer=2自然非法了

    所以归根结底jdk从语法上避免了这个问题的发生

    5 扩展思考

    public class TestMain {
    
        private volatile TestC testC;
    
        private static class TestC {
            private Integer integer;
    
            public Integer getInteger() {
                return integer;
            }
    
            public void setInteger(Integer integer) {
                this.integer = integer;
            }
        }
    }
    

      

    这个代码能保证integer的可见性吗,答案是不能,volatile修饰的是testC,而不是integer,这个性质有点像Unsafe控制ConcurrentHashMap内并发数组元素的可见性   ,数组对象volatile,数组元素没有volatile,数组元素一样会有可见性问题

    6

        public static void main(String []f) {
            TestC testC = new TestC();
            testC.setInteger(1);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testC.setInteger(2);
                }
            }).start();
            while(true) {
                if(testC.getInteger() == 2) break;
            }
        }
    
        private static class TestC {
            private Integer integer;
    
            public Integer getInteger() {
                return integer;
            }
    
            public void setInteger(Integer integer) {
                this.integer = integer;
            }
        }
    

      

    这个代码是否实现了第2点所说的“局部变量跨线程写入”?

    对不起,这个不属于写入,这里的“写入”指的是,让共享变量作为=的左值,此之谓“写入”,比如:

        public static void main(String []f) {
            TestC testC = new TestC();
            testC.setInteger(1);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    TestC tmp = new TestC();
                    tmp.setInteger(2);
                    testC = tmp;
                }
            }).start();
            while(true) {
                if(testC.getInteger() == 2) break;
            }
        }
    
        private static class TestC {
            private Integer integer;
    
            public Integer getInteger() {
                return integer;
            }
    
            public void setInteger(Integer integer) {
                this.integer = integer;
            }
        }
    

      

    此时又会报,要加final的提示

    我们得到重要结论:局部变量永远不能被多线程写入,既然无法多线程写入,自然也没有可见性问题

  • 相关阅读:
    【贪心】CodeForces-545C:Woodcutters
    【贪心】雷达问题
    【贪心】poj1328:雷达设置
    【最短路】HDU2680:Choose the best route
    2018年第四阶段组队训练赛第九场
    第四阶段组队训练赛第八场
    2018年第四阶段组队训练赛第七场
    第四阶段组队训练赛第六场( 题源:UKIEPC2017)
    Coins I
    2018年第四阶段组队训练赛第五场
  • 原文地址:https://www.cnblogs.com/silyvin/p/14964075.html
Copyright © 2011-2022 走看看