笔记 35 | java线程之线程安全与非线程安全

地址

CSDN http://blog.csdn.net/xiangyong_1521/article/details/78541142


线程安全与非线程安全

ArrayList和VectorHashMap和HashTableStringBuilder和StringBuffer这些有什么区别?

这些面试题常被问,答案是,左边的都是非线程安全,右边都是线程安全!

然后又问你,什么是线程安全,什么是非线程安全呢?

A.线程安全

当多个线程类并发操作某类的方法A,来修改这个A方法的某个成员变量的值B,B不会出错,则我们就说,该的这个A方法是线程安全的。   某类的某方法是否线程安全的关键是:   (1) 该方法是否修改该类的成员变量;   (2) 是否给该方法加锁(是否用synchronized关键字修饰)。

B.非线程安全

当多个线程类并发操作某类的方法A,来修改这个A方法的某个成员变量的值B,B会出错,则我们就说,该的这个A方法是非线程安全的。


synchronized

如果要把这个方法变成线程安全的,则用 synchronized关键字来修饰该方法即可:

class counnt{
        private int count = 0;

        /*
         * 当有多个线程类同时操作这个方法是,就容易出问题
         */
        public void add(){
            count++;
        }

        /*
         * 当加了synchronized修饰后,就是线程安全的了,不过性能很低
         */
        public synchronized void adds(){
            count++;
        }
    }

例子理解:

public Double dou(){
        int a = 5;
        int b = 2;
        return new Double(a/b);
    }

在执行这个方法时,每一个线程都有自己的独立的栈区。当线程进入到方法执行断的时候,一个方法变量在方法代码段中被创建,并保存在线程的栈区(静态方法也放在这里)。不同线程执行这段代码时,会有不同的a/b变量。所以这里是线程安全的,因为没有数据共享。

考虑下面的例子,多线程情况下只执行一次并可以重用结果:

private Double dou;
    public Double dou(){
        int a = 5;
        int b = 2;
        if (dou == null) {
            dou = new Double(a/b);
        }
        return dou;
    }

这个地方虽然优化了,但可惜他不是线程安全的。两个线程并发执行的时候同时进入到dou ==null这个位置,这样可能会new出一个脏的数据。

private static ThreadLocal local = new ThreadLocal();
    public Double dou(){
        int a = 5;
        int b = 2;
        if (local.get() == null) {
            local.set(new Double(a/b));
        }
        return (Double)local.get();
    }

ThreadLocal类封装了任何类型对象,并把它绑定到当前线程。线程执行dou()方法的时候,实例pi返回的是当前线程的对象。这样的调用是线程安全的。

线程安全跟非线程安全如何取舍

从第一个例子可得知,非线程的方法添加synchronized修饰就可以转化为线程安全,但是性能会相差20倍左右,如果不加的话,该类的成员变量又可能发生错误,所以具体就看你的需求,一个是否有很多线程操作这个方法,一个是否注重它的性能!

原文发布于微信公众号 - 项勇(xiangy_life)

原文发表时间:2017-11-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的Python和你

Python数据分析之groupby语法糖对分组进行迭代语法糖一:选取一个或多个列

1414
来自专栏一个会写诗的程序员的博客

Shell 极简教程Hello World变量函数运算符字符串数组for 循环if elseShell test 命令

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

1091
来自专栏nnngu

015 反射中的 Class.forName() 与 ClassLoader.loadClass() 的区别

Class.forName() 与 ClassLoader.loadClass() 大家都知道是反射用来构造类的方法,但是他们的用法还是有一定区别的。 在讲区别...

2643
来自专栏海天一树

NOIP 2018普及组复赛第1题答案详解

本题考察的知识点有两个: (1)输入带空格的字符串 常用的scanf和cin,遇到第一个空格就会停止输入。 C语言可以使用gets()输入带空格的字符串。当然使...

3945
来自专栏Golang语言社区

Golang语言的函数调用信息

函数的调用信息是程序中比较重要运行期信息, 在很多场合都会用到(比如调试或日志). Go语言 runtime 包的 runtime.Caller / runti...

5586
来自专栏linux运维学习

linux学习第六十四篇:Shell脚本中的逻辑判断,文件目录属性判断, if特殊用法,case判断

Shell脚本中的逻辑判断 格式1:if 条件 ; then 语句; fi 格式2:if 条件; then 语句; else 语句; fi 格式3:if …; ...

3216
来自专栏linux系统运维

正则介绍以及grep

1323
来自专栏好好学java的技术栈

java基础提升篇:synchronized同步块和volatile同步变量

862
来自专栏转载gongluck的CSDN博客

Lua学习笔记

--Lua笔记-- --0.Lua开篇-- --http://www.cnblogs.com/stephen-liu74/archive/2012/06/11/...

6206
来自专栏C#

解析.NET对象的跨应用程序域访问(上篇)

   在目前的项目开发中,分布式开发已经逐渐成为主流。一个项目要是没有采用分布式架构,都不好意思跟别人说这是一个完整的项目。这句话虽然有些过激,但是随着人们对效...

2215

扫码关注云+社区

领取腾讯云代金券