• 局部变量的可见性


    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的提示

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

  • 相关阅读:
    substring(x)和substring(x,y)的用法
    js 判断字符串中是否包含某个字符串
    js如何将纯数字字符串转换为long型
    union和union all的区别
    JavaScript 中 var 和 let 和 const 关键字的区别
    JS操作文件
    java 字符串和集合互相转换
    关于sql中in 和 exists 的效率问题,in真的效率低吗
    sql 同一张表查询不同数据合并之后关联查询
    Android input输入框 移动页面input手机键盘中的“搜索”按键
  • 原文地址:https://www.cnblogs.com/silyvin/p/14964075.html
Copyright © 2020-2023  润新知