zoukankan      html  css  js  c++  java
  • 线程安全

    2 线程安全

    核心就是在访问对象的可变状态时,进行正确的管理。

    2.1 对象及状态

    对象的状态(也可理解为属性)是指存储在状态变量(例如实例或静态域)中的数据。对象的状态可能包括其他依赖对象的域。例如,某个HashMap的状态不仅存储在HashMap对象本身,还包含集合里面存储的对象。

    如何安全地访问可变状态的变量?

    A: 不在多个线程之间共享(定义为私有)

    B:定义为final

    C: 使用同步

     

    在线程安全的类当中封装了必要的同步机制,客户端无需重复采用同步措施。

     

    2.2 原子性

    在java.util.concurrent.atomic包中包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。

    类摘要

    AtomicBoolean

    可以用原子方式更新的 boolean 值。

    AtomicInteger

    可以用原子方式更新的 int 值。

    AtomicIntegerArray

    可以用原子方式更新其元素的 int 数组。

    AtomicIntegerFieldUpdater<T>

    基于反射的实用工具,可以对指定类的指定 volatile int 字段进行原子更新。

    AtomicLong

    可以用原子方式更新的 long 值。

    AtomicLongArray

    可以用原子方式更新其元素的 long 数组。

    AtomicLongFieldUpdater<T>

    基于反射的实用工具,可以对指定类的指定 volatile long 字段进行原子更新。

    AtomicMarkableReference<V>

    AtomicMarkableReference 维护带有标记位的对象引用,可以原子方式对其进行更新。

    AtomicReference<V>

    可以用原子方式更新的对象引用。

    AtomicReferenceArray<E>

    可以用原子方式更新其元素的对象引用数组。

    AtomicReferenceFieldUpdater<T,V>

    基于反射的实用工具,可以对指定类的指定 volatile 字段进行原子更新。

    AtomicStampedReference<V>

    AtomicStampedReference 维护带有整数"标志"的对象引用,可以用原子方式对其进行更新。

     

    2.3 竞态条件

    2.3.1先检查后执行

    当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。最常见的竞态条件类型就是"先检查后执行(Check-Then-Act )"操作,即通过一个可能失效的观测结果来决定下一步的动作。

    线程B同时执行getInstanceo A看到instance为空,因而创建一个新的ExpensiveObject实

    例。B同样需要判断instance是否为空。此时的instance是否为空,要取决于不可预测的时序,包括线程的调度方式,以及A需要花多长时间来初始化ExpensiveObject并设置instance。如果当B检查时,instance为空,那么在两次调用getInstance时可能会得到不同的结果,即使getInstance通常被认为是返回相同的实例。

     

    2.3.2读取—修改—写入

     

    2.4 数据竞争

    如果在访问共享的非final类型的域时没有采用同步来进行协同,那么就会出现数据竞争。当一个线程写人一个变量而另一个线程接下来读取这个变量,或者读取一个之前由另一个线程写人的变量时,并且在这两个线程之间没有使用同步,那么就可能出现数据竞争。在Java内存模型中,如果在代码中存在数据竞争,那么这段代码就没有确定的语义。并非所有的竞态条件都是数据竞争,同样并非所有的数据竞争都是竟态条件,但二者都可能使并发程序失败。

     

    2.5 加锁机制

    A: 对于有多个状态(属性)的对象,每一个可变状态都要加锁。

    B: 长时间的或者可能无法完成的操作,不要持有锁,一般单独封装在一个线程,提交到池。

    2.5.1 内置锁Synchronized

    Java提供了一种内置的锁机制来支持原子性。同步代码块(Synchronized Block)。

    同步代码块包括两部分:一个作为锁的对象引用,一个作为由这个锁保护的代码块。

     

    2.5.2 内置锁重入

    重入:如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。

    意味着获取锁的操作的粒度是"线程",而不是"调用"。重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁就被认为是没有被任何线程持有。每个锁对应一个标记(0/1)和持有者线程名。

     

     

  • 相关阅读:
    UIApplication详解
    判断iPhone和iPad 判断设备版本
    UIDeviceOrientation UIInterfaceOrientation 区别
    iphone跬步之--NSBundle
    iOS 开发者证书总结
    iOS开发:创建真机调试证书
    iOS符号表 http://help.bugtags.com/hc/kb/article/68470/
    MRC BlOCK ARC
    调用[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad判断设备
    sql server 代理(已禁用代理xp)解决办法
  • 原文地址:https://www.cnblogs.com/domi22/p/8538114.html
Copyright © 2011-2022 走看看