线程安全

今天看到这么个写法 internal System.Collections.ArrayList lastResults = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));java

想起了线程安全, 想来复习一下,如下摘自百度百科,有删减:安全

 

1. 概述多线程

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

或者说:一个类或者程序所提供的接口对于线程来讲是原子操做或者多个线程之间的切换不会致使该接口的执行结果存在二义性,也就是说咱们不用考虑同步的问题。线程

线程安全问题都是由全局变量静态变量引发的。设计

若每一个线程中对全局变量静态变量只有读操做,而无写操做,通常来讲,这个全局变量是线程安全的;如有多个线程同时执行写操做,通常都须要考虑线程同步,不然的话就可能影响线程安全。orm

2. 安全性htm

类要成为线程安全的,首先必须在单线程环境中有正确的行为。若是一个类实现正确(这是说它符合规格说明的另外一种方式),那么没有一种对这个类的对象的操做序列(读或者写公共字段以及调用公共方法)可让对象处于无效状态,观察到对象处于无效状态、或者违反类的任何不可变量、前置条件或者后置条件的状况。对象

此外,一个类要成为线程安全的,在被多个线程访问时,无论运行时环境执行这些线程有什么样的时序安排或者交错,它必须仍然有如上所述的正确行为,而且在调用的代码中没有任何额外的同步。其效果就是,在全部线程看来,对于线程安全对象的操做是以固定的、全局一致的顺序发生的。接口

正确性与线程安全性之间的关系很是相似于在描述 ACID(原子性、一致性、独立性和持久性)事务时使用的一致性与独立性之间的关系:从特定线程的角度看,由不一样线程所执行的对象操做是前后(虽然顺序不定)而不是并行执行的。

3. 安全程度

线程安全性不是一个非真即假的命题。 Vector 的方法都是同步的,而且 Vector 明确地设计为在多线程环境中工做。可是它的线程安全性是有限制的,即在某些方法之间有状态依赖(相似地,若是在迭代过程当中 Vector 被其余线程修改,那么由 Vector.iterator() 返回的 iterator会抛出ConcurrentModifiicationException)。

对于 Java 类中常见的线程安全性级别,没有一种分类系统可被普遍接受,不太重要的是在编写类时尽可能记录下它们的线程安全行为。

Bloch 给出了描述五类线程安全性的分类方法:不可变、线程安全、有条件线程安全、线程兼容和线程对立。只要明确地记录下线程安全特性,那么您是否使用这种系统都不要紧。这种系统有其局限性 -- 各种之间的界线不是百分之百地明确,并且有些状况它没照顾到 -- 可是这套系统是一个很好的起点。这种分类系统的核心是调用者是否能够或者必须用外部同步包围操做(或者一系列操做)。下面几节分别描述了线程安全性的这五种类别。

不可变

不可变的对象必定是线程安全的,而且永远也不须要额外的同步[1] 。由于一个不可变的对象只要构建正确,其外部可见状态永远也不会改变,永远也不会看到它处于不一致的状态。Java 类库中大多数基本数值类如 Integer 、 String 和 BigInteger 都是不可变的。

须要注意的是,对于Integer,该类不提供add方法,加法是使用+来直接操做。而+操做是不具线程安全的。这是提供原子操做类AtomicInteger的缘由。

线程安全

线程安全的对象具备在上面“线程安全”一节中描述的属性 -- 由类的规格说明所规定的约束在对象被多个线程访问时仍然有效,无论运行时环境如何排列,线程都不须要任何额外的同步。这种线程安全性保证是很严格的 -- 许多类,如 Hashtable 或者 Vector 都不能知足这种严格的定义。

有条件的

有条件的线程安全类对于单独的操做能够是线程安全的,可是某些操做序列可能须要外部同步。条件线程安全的最多见的例子是遍历由 Hashtable 或者 Vector 或者返回的迭代器 -- 由这些类返回的 fail-fast 迭代器假定在迭代器进行遍历的时候底层集合不会有变化。为了保证其余线程不会在遍历的时候改变集合,进行迭代的线程应该确保它是独占性地访问集合以实现遍历的完整性。一般,独占性的访问是由对锁的同步保证的 -- 而且类的文档应该说明是哪一个锁(一般是对象的内部监视器(intrinsic monitor))。

若是对一个有条件线程安全类进行记录,那么您应该不只要记录它是有条件线程安全的,并且还要记录必须防止哪些操做序列的并发访问。用户能够合理地假设其余操做序列不须要任何额外的同步。

线程兼容

线程兼容类不是线程安全的,可是能够经过正确使用同步而在并发环境中安全地使用。这可能意味着用一个 synchronized 块包围每个方法调用,或者建立一个包装器对象,其中每个方法都是同步的(就像 Collections.synchronizedList() 同样)。也可能意味着用 synchronized 块包围某些操做序列。为了最大程度地利用线程兼容类,若是全部调用都使用同一个块,那么就不该该要求调用者对该块同步。这样作会使线程兼容的对象做为变量实例包含在其余线程安全的对象中,从而能够利用其全部者对象的同步。

许多常见的类是线程兼容的,如集合类 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 类 Connection 和 ResultSet 。

线程对立

线程对立类是那些不论是否调用了外部同步都不能在并发使用时安全地呈现的类。线程对立不多见,当类修改静态数据,而静态数据会影响在其余线程中执行的其余类的行为,这时一般会出现线程对立。线程对立类的一个例子是调用 System.setOut() 的类。