软件构造 并发3(线程安全性)

线程安全:数据类型或静态方法在多线程中执行时,无论如何执行,不需调用者做额外的协作仍可以得到正确的行为。

                 行为正确意味着满足规格说明和保持不变性   不能在前置条件中对调用者增加时间性要求(在set()运行时不能调用get())

                 例子:迭代器, 不是线程安全的。 迭代器的规范说,不能在迭代它的同时修改一个集合。 这是一个与调用者相关的时间相关的前提条件,如果违反它,Iterator不保证行为正确

线程安全的四个方法:①限制可变变量的共享②用不可变的共享变量③将共享数据封装在线程安全的数据类型中④使用同步来防止线程同时访问变量

限制可变变量的共享:通过将数据限制在单个线程中,可以避免线程在可变数据上进行竞争。可变量的共享是竞争的主要原因

                                   ①局部变量保存在线程栈中,每个调用都有自己的变量副本 ,每个线程都有自己的堆栈。

                                   ②局部变量如果是对象的引用,则要确保不能引用任何其他线程可访问 的对象。

                                   避免全局变量:全局静态变量不会自动受到线程访问限制。如果使用了全局静态变量,应说明只有一个线程会使用它们。最好在多线程环境中取消全局静态变量

                                   两个线程若同时调用一个返回类的公众静态方法,会产生两个实例,破坏了表示不变性。改造:采用限制的方式并自行确保只有一个线程访问该方法;采用synchronized方式

                                   HashMap也不是线程安全的

用不可变的共享变量:使用不可变的引用和数据类型。不可变解决了因为共享可变数据造成的竞争,并简单地通过使共享数据不可变来解决它。

                                    final变量是不可变的引用,所以声明为final的变量可以安全地从多个线程访问。(只能读不能写   因为这种安全性只适用于变量本身,仍然必须确保变量指向的对象是不可变的)

                                   回忆不变性:类型是不可变的:如果类型的对象在其整个生命周期中始终表示相同的抽象值

                                                         但实际上,允许对rep进行改变,只要这些改变对客户是不可见的,并且对应的抽象值不变(有益的突变)但是对于并发性,这种隐藏的变化是不安全的 , 使用有益的变  

                                                         化的不可变数据类型必须使用锁使自己线程安全。

将共享数据封装在线程安全的数据类型中与不安全类型相比,线程安全数据类型通常会导致性能损失

                                                                      线程安全的集合(Collections)List Set Map ArrayList HashMap HashSet都不是线程安全的

                                                                      java提供了线程安全的Collections类版本:方法是原子的,(原子方法:动作的内部操作不会同其他操作交叉,不会产生部分完成的情况)

                                                                                                                                             private static Map<Integer,Boolean> cache =  Collections.synchronizedMap(new HashMap<>());

                                                                                                                                             新的HashMap只传递给synchronizedMap,并且永远不会存储 在其他地方。

                                                                      迭代器也不是线程安全的:使用iterator()或for循环语法也是不安全的,在需要迭代它时获取集合的锁。原子 操作不足以完全防止竞争
                                                                      线程安全包装:

通过共享可变数据的竞争条件实现安全的三种主要方式:①限制可变变量的共享②用不可变的共享变量③将共享数据封装在线程安全的数据类型中

 

                 

 

posted on 2018-06-18 22:54  hitxgl  阅读(301)  评论(0编辑  收藏  举报