1.java面试问题 之 基础类型属性(int)能否线程安全?

作者 : 开心源码 本文共2850个字,预计阅读时间需要8分钟 发布时间: 2022-05-13 共225人阅读

脑海第一感觉 static int 公告的属性肯定是非线程安全的。int直接公告的属性难道也是非线程安全吗?(疑问)。
通过题面意思就能感觉到面试官的用意,他就是想让你说是非线程安全的。而后他好问为什么。结果我直接说不知道。说实话真拿不准,于是自己通过实践验证得出了少量结论并记录下来。加申印象。

private static int value = 1;private int value = 1;

以下想通过实践证实几点:
1.两种公告方式能否线程安全。
2.总结两种方式的区别。

第一两种公告方式能否线程安全。

证实1:private static int value = 1; 非线程安全

/** * 证实static int 公告属性为非线程安全的类 */class TTT {        static int value = 1;   //注释1:Integer value = new Integer(1) 同样    public int get1() throws InterruptedException {                Thread.sleep(10);   //注释2:值越大重复值越多                return value++;    }    }/** * 测试类 */public class Test2 {        public static void main(String[] args)  {                TTT t = new TTT();  //注释3:实例化一个对象,并通过多个线程调用 get1 方法。                for(int i=1; i<=1000; i++) {            new Thread(new Runnable() {                                @Override                public void run() {                                        try {                        System.out.println(t.get1());                    } catch (Exception e) {                    }                                    }                            }).start();        }    }}

期望结果:1 – 1000
实际结果:1 – x (<1000) 实际输出结果中存在重复值

将已上代码片段稍作调整再次验证。
注释3处,实例化对象挪到线程run方法体内

/** * 证实static int 公告属性为非线程安全的类 */class TTT {        static int value = 1;   //注释1:Integer value = new Integer(1) 同样    public int get1() throws InterruptedException {                Thread.sleep(10);   //注释2:值越大重复值越多                return value++;    }    }/** * 测试类 */public class Test2 {        public static void main(String[] args)  {                        for(int i=1; i<=1000; i++) {            new Thread(new Runnable() {                                @Override                public void run() {                    TTT t = new TTT();  //注释3:实例化1000个对象,并调用 get1 方法。                                        try {                        System.out.println(t.get1());                    } catch (Exception e) {                    }                                    }                            }).start();        }            }    }

期望结果:1 – 1000
实际结果:1 – x (<1000) 实际输出结果中存在重复值

结论:已上两种情况相同针对 private static int value = 1; 都是非线程安全的。

那么都知道通过synchronized关键字可以将get1方法改为线程安全的。分别在两段代码片段中的get1方法加上synchronized关键字,但是结果却又不同了

  • 第一段代码 实例化一个对象,并通过1000个线程调用 get1 方法,synchronized关键字起作用的。
  • 第二段代码 通过1000个线程实例化1000个对象,并调用 get1 方法,synchronized关键字不起作用。

补充:synchronized关键字在多线程情况下针对同一个实例(对象Object)是起作用的。

证实2:private int value = 1; 非线程安全

/** * 证实 int 公告属性为非线程安全的类 */class TT {        private int value = 1;  //Integer value = new Integer(1) 同样    public int get1() throws Exception {                Thread.sleep(10);   //值越大重复值越多                return value++;    }    }/** * 测试类 */public class Test {    public static void main(String[] args) throws Exception {                TT t = new TT();    //注释3:实例化一个对象,并通过多个线程调用 get1 方法。                for(int i=1; i<=1000; i++) {            new Thread(new Runnable() {                                @Override                public void run() {                    try {                        System.out.println(t.get1());                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }).start();        }            }    }

期望结果:1 – 1000
实际结果:1 – x (<1000) 实际输出结果中存在重复值

同样将已上代码片段稍作调整再次验证。
注释3处,实例化对象挪到线程run方法体内

/** * 证实 int 公告属性为非线程安全的类 */class TT {        private int value = 1;  //Integer value = new Integer(1) 同样    public int get1() throws Exception {                Thread.sleep(10);   //值越大重复值越多                return value++;    }    }/** * 测试类 */public class Test {    public static void main(String[] args) throws Exception {                        for(int i=1; i<=1000; i++) {            new Thread(new Runnable() {                                @Override                public void run() {                                        TT t = new TT();    //注释3:实例化1000个对象,并调用 get1 方法。                                        try {                        System.out.println(t.get1());                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }).start();        }            }    }

实际结果:输出的一律是 1

结论:针对 private int value = 1;

  • 第一段代码 实例化一个对象,并通过1000个线程调用 get1 方法,value值非线程安全。
  • 第二段代码 通过1000个线程实例化1000个对象,并调用 get1 方法,value值线程安全。

补充:在多线程情况下针对同一个实例(对象Object)内的基础类型公告的属性 进行调用是非线程安全的。

总结两种方式的区别。
  1. 静态属性相对于类(class)是非线程安全的。如上结论无论实例化一个对象,并通过多线程调用方法。还是通过多线程实例化多个对象,调用方法结果是一样的。
  2. 一般属性相对于对象(object)是非线程安全的。如上结论,实例化一个对象,并通过多个线程调用方法获取属性值,值是不可靠的。而实通过线程实例化多个对象,并调用方法获取属性值,值是可靠的。

具体理论可参考jvm实战第二章内存管理。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 1.java面试问题 之 基础类型属性(int)能否线程安全?

发表回复