编程语言
首页 > 编程语言> > 并发编程-线程安全策略之常见的线程不安全类

并发编程-线程安全策略之常见的线程不安全类

作者:互联网

脑图

在这里插入图片描述

概述 

前两篇博客,我们说了 通过 不可变变量 和 线程封闭 这两种方式来实现线程安全。

这里我们来介绍下很常见的线程不安全的类

所谓线程不安全的类,是指一个类的实例对象可以同时被多个线程访问,如果不做同步或线程安全的处理,就会表现出线程不安全的行为,比如逻辑处理错误、抛出异常等。

字符串拼接之StringBuilder、StringBuffer

StringBuilder (线程不安全)

在这里插入图片描述

运行结果

在这里插入图片描述 

结果不等于5000,在多线程情况下,StringBuild是线程不安全的. 

StringBuffer (线程安全)

在这里插入图片描述

运行结果

在这里插入图片描述 结果等于5000,在多线程情况下,StringBuffer是线程安全的.

 小结

既然StringBuffer是线程安全的, 那为何JDK还要提供StringBuilder呢?

StringBuffer之所以是线程安全的原因是几乎所有的方法都加了synchronized关键字,所以是线程安全的。 synchronized 同一时间只能有一个线程访问,所以性能会相对较差。

在上篇博文 并发编程-线程安全策略之线程封闭中,我们了解到 线程封闭可以确保线程安全,其中线程封闭的一种实现方式时堆栈封闭,说白了就是局部变量。

所以推荐在堆栈封闭等线程安全的环境下(方法中的局部变量)应该首先选用StringBuilder。

时间相关的类 SimpleDateFormat、第三方库joda-time、JDK8提供的类

SimpleDateFormat 的实例对象在多线程共享使用的时候会抛出转换异常,正确的使用方法应该是采用堆栈封闭,将其作为方法内的局部变量而不是全局变量,在每次调用方法的时候才去创建一个SimpleDateFormat实例对象,这样利用堆栈封闭就不会出现并发问题。

另一种方式是使用第三方库joda-time的DateTimeFormatter类 或者JDK8新提供的类 : 不可变类且线程安全 LocalDate 、java.time.LocalTime 和LocaldateTime 新的Date和Time类DateTimeFormatter

SimpleDateFormat (线程不安全的写法)

在这里插入图片描述

执行结果:表现出了异常
在这里插入图片描述 

SimpleDateFormat (线程安全的写法-堆栈封闭)

在这里插入图片描述 

没有抛出异常

在这里插入图片描述 线程安全,无异常

 joda-time (线程安全)

在这里插入图片描述

线程安全,无异常

JDK8的时间处理类(线程安全)

在这里插入图片描述 

线程安全,无异常

Collections 中线程不安全的类

通常情况下,我们都是在方法内部作为局部变量使用这些集合类,很少会触发线程不安全的问题。

如果在某些情况下定义成static,而且多个线程可以修改的时候就容易出现多线程不安全的问题。

 ArrayList (线程不安全)

在这里插入图片描述

计数错误,线程不安全

在这里插入图片描述 

HashSet (线程不安全)

在这里插入图片描述 

 计数错误,线程不安全

在这里插入图片描述

HashMap (线程不安全)

在这里插入图片描述 

计数错误,线程不安全

在这里插入图片描述 

注意事项 (先检查后执行-- 线程不安全)

有一种写法需要注意,即便是线程安全的对象,在这种写法下也可能会出现线程不安全的行为,这种写法就是先检查后执行 

if(condition(a)){
    handle(a);
}

在这个操作里,可能会有两个线程同时通过if的判断,然后去执行了处理方法,那么就会出现两个线程同时操作一个对象,从而出现线程不安全的行为。这种写法导致线程不安全的主要原因是因为这里分成了两步操作,这个过程是非原子性的,所以就会出现线程不安全的问题。

标签:安全类,封闭,StringBuffer,安全策略,SimpleDateFormat,安全,线程,StringBuilder
来源: https://blog.csdn.net/K_520_W/article/details/119278592