# 其他-Java中的线程安全

简单的介绍在Java中的线程安全(Thread-Safe)和线程不安全以及线程安全和不安全的集合对象,还有一个通俗易懂的小例子


# 概念

  • 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的

# 工作原理

  • JVM有一个Main Memory,而每个线程有自己的Working Memory,一个线程对一个变量进行操作时,都要在自己的Working Memory里面建立一个Copy,操作完之后再写入Main Memory。多个线程同时操作同一个变量,就可能会出现不可预知的结果。所以,当线程一起并发运行时,同时对一个数据进行修改,就可能会造成数据的不一致性(多个线程先后更改数据造成所得到的数据是脏数据)

# 解决方法

多线程并发不安全的原因已经知道,那么针对这个种情况,有两种解决思路

  • 给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用
  • 让线程也拥有资源(副本),不用去共享进程中的资源(副本)

基于上面的两种思路,下面便是三种实施方案

  • 多实例或者是多副本(ThreadLocal),对应着思路二,ThreadLocal可以为每个线程的维护一个私有的本地变量,可参考Java线程副本–ThreadLocal
  • 使用锁机制synchronizelock方式,为资源加锁
  • 使用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。这就是线程不安全
上次更新时间: 2023-12-15 03:14:55