# 其他-Java中的线程安全
简单的介绍在Java中的线程安全(Thread-Safe)和线程不安全以及线程安全和不安全的集合对象,还有一个通俗易懂的小例子
# 概念
- 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的
# 工作原理
- JVM有一个Main Memory,而每个线程有自己的Working Memory,一个线程对一个变量进行操作时,都要在自己的Working Memory里面建立一个Copy,操作完之后再写入Main Memory。多个线程同时操作同一个变量,就可能会出现不可预知的结果。所以,当线程一起并发运行时,同时对一个数据进行修改,就可能会造成数据的不一致性(多个线程先后更改数据造成所得到的数据是脏数据)
# 解决方法
多线程并发不安全的原因已经知道,那么针对这个种情况,有两种解决思路
- 给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用
- 让线程也拥有资源(副本),不用去共享进程中的资源(副本)
基于上面的两种思路,下面便是三种实施方案
- 多实例或者是多副本(ThreadLocal),对应着思路二,ThreadLocal可以为每个线程的维护一个私有的本地变量,可参考Java线程副本–ThreadLocal
- 使用锁机制synchronize或lock方式,为资源加锁
- 使用java.util.concurrent下面的类库,有JDK提供的线程安全的集合类
# 线程安全的集合对象
- Vector
- HashTable
- StringBuffer
# 非线程安全的集合对象
- ArrayList
- LinkedList
- HashMap
- HashSet
- TreeMap
- TreeSet
- StringBulider
# 举例
- 在单线程运行的情况下,如果Size = 0,添加一个元素后,此元素在位0,而且Size = 1
- 如果是在多线程情况下,比如有两个线程,线程A先将元素存放在位置0。但是此时CPU调度线程A暂停,线程B得到运行的机会。线程B也向此ArrayList添加元素,因为此时Size仍然等于0(注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加Size的值。那好,现在我们来看看ArrayList的情况,元素实际上只有一个,存放在位置0,而Size却等于2。这就是线程不安全了