- 线程安全:当多个线程访问同一个类的时候,如果不考虑这些线程的运行环境下的调度和交替执行,并且不需要额外的同步以及在调用方代码不必做其他的协调,这个的行为仍然是正确的,那么称之为线程安全、
- 无状态对象永远是线程安全的。
- 锁保护:对于每个可被多线程访问的可变状态变量,如果所有访问他的线程在执行时都占有同一个锁,这种情况下我们称这个变量是由这个锁保护的。
- 对于每个涉及多个变量的不变约束,需要同一个锁保护其所有的变量。
- 锁不仅仅是关于同步和互斥的,也是关于内存可见的。为了保证所有的线程都能够看到共享的,可变变量的最新值,读取和写入线程必须使用公共的锁进行同步
- 加锁可以保证可见性和原子性,volatile只能保证可见性
-
volatile只有满足下面所有的标准后,才可以使用
1.写入变量时并不依赖变量的当前值;或者能够确保只有单一线程修改变量的值2.变量不需要与其他的状态变量共同参与不变约束;3.而且,访问变量时,没有其他的原因需要加锁。
- 不可变对象可以在没有额外同步的情况下,安全地用于任意线程;甚至发布(publish)他们时也不需要同步。(满足:不可以修改的状态、所有域都是final类型以及正确的构造。)
-
为了安全的生产/发布(publish)对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确创造的对象可以通过下列条件安全的生产(即可见性的要求):
通过静态初始化器初始化对象的引用将他的引用存储到volatile域或者AtomicReference将他的引用存储到正确创建对象的final域中或者将他的引用存储到由锁正确保护的域中
- 一个对象在技术上是可变的,但是他的状态不会在发布后被修改,这样的对象称作有效/高效不可变对象(PS:Date对象)
- 任何线程都可以在没有额外的同步下安全的使用一个安全生产的(publish)高效的(effectively)不可变对象
-
发布对象的必要条件依赖于对象的可变性(不可变:技术上,状态上都不变;高效不可变:技术上可变,状态上不变;可变:都可变)
不可变对象可以通过任何机制发布高效不可变对象必须要安全发布可变对象必须要安全发布,同时必须要线程安全或者被锁保护
-
在并发程序中,使用对象和共享对象的一些有效的策略如下:
线程限制:一个线程限制对象就是说线程独自占有,限制该对象在这个线程,只能被拥有他的这个线程所修改。共享只读( Shared read-only):一个共享只读对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不可以修改他,共享只读对象包括可变对象和高效不可变对象。共享线程安全( Shared thread-safe):一个线程安全的对象在内部进行同步,所有其他线程无需额外同步,就可以通过公共接口随意的访问他。被守护的:一个被守护的对象只能通过特定的锁访问,被守护的对象包括哪些被线程安全对象封装的对,和已知被特定的锁保护起来的已发布对象。
- 对象的状态:一个对象的所有原始类型组成了这个对象的状态,如果对象中的域引用了其他的对象,那么其他对象中的
- 实例限制:一个对象A被另一个对象B封装,可用吧A限制在类实例(私有变量),语汇范围(本地变量)或者线程中(对象在线程内部从一个方法到另一个方法,前提是该对象不被跨线程共享)。
- 实例限制,是构建线程安全类的最简单的方法之一。(成员变量定义为final,Collections.synchronizedList以及同族方法提供了包装起把ArrayList,HashMap这样线程不安全的转为线程安全的用法)
- 将数据封装在对象内部,把对数据的访问限制在对象的方法上,更易于确保线程在访问数据时总能获得正确的锁。
- 如果一个类由多个彼此独立的线程安全的状态变量组成,并且类的操作不包含任何无效状态转换时,可以将线程安全委托给这些状态变量。(彼此独立的线程安全的状态变量,简单的理解就是每个变量都是线程安全的,并且彼此之间的状态转换都是有效的,不相互影响和约束)
- 如果一个状态变量是线程安全的,没有任何的不变约束限制他的值,并且没有任何状态转换限制他的操作,那么他是可以安全发布的。
- 同步容器,并发容器(同步。异步、并发的区别。同步是按照一定的规则持续执行,synchronize这样字段保证一致性。异步就是不需要柱塞,不需要等待处理完成。)
- 同步容器:Hashtable和Vector;由collections.synchronizedXXX工厂方法创建的。
- 并发容器:concurrentHashMap(代替同步的哈希map的实现,还加入了常见的复合操作“缺少即加入”),copyOnWriteArrayList(是List相应的同步实现),java5.0新增了Queue和blockingQueue。实现接口有concurrentLinkedQueue(FIFO队列),priorityQueue(非并发具有优先级顺序的队列)。blockingQueue是扩展了queue,增加了可阻塞的插入获取。阻塞队列在生产者-消费者设计中非常有用。