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

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

  • 相关阅读:
    Redis 常用命令整理
    TCP系列01—概述及协议头格式
    TCP/IP详解--TCP网络传输数据包1460MSS和1448负载
    TCP中报文段大小(MSS)、MTU
    DNS 过滤脚本
    TCP SYN Cookies – DDoS defence
    python virtualenv venv 虚拟环境
    git 命令总结
    王兴三横四纵
    获取国税门户可供下载的资源文档
  • 原文地址:https://www.cnblogs.com/silyvin/p/14964075.html
Copyright © 2011-2022 走看看