zoukankan      html  css  js  c++  java
  • 知识树——线程安全

    1 线程安全的定义
    当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。
     
    2 使用和共享对象时保证线程安全的方法
     
    2.1 同步锁
     
    2.1.1 synchronized
     
    2.1.2 ReentrantLock
    增加了一些高级功能,如:等待可中断、可实现公平锁,锁可以绑定多个条件。
     
    2.2 乐观锁
    CAS
     
    2.3 线程封闭
    线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改。
     
    2.3.1 栈封闭
    只通过局部变量访问对象。
     
    2.3.2 ThreadLocal类
    推荐方法。其核心类是ThreadLocalMap(一个自定义hash map,但并非继承HashMap),Thread的成员变量,key为ThreadLocal。
     
    2.4 只读共享
    可以由多个线程并发访问,但任何线程都不能修改它。
     
    2.4.1 不可变对象
    1. 将类和所有状态变量设为final。
    2. 对象是正确创建的(创建期间this引用没有逸出)。
    3. 不提供修改状态变量的方法,且暴露状态变量时只暴露状态变量的拷贝。 
     
    2.4.2 事实不可变对象
    技术上可变,业务上不变。必须通过安全方式发布。
     
    2.5 线程安全共享
    在对象内部实现同步。
     
    3 安全发布对象的方法
    注:不可变对象可通过任何机制发布
     
    3.1 在静态初始化函数中初始化一个对象引用
    静态初始化器由JVM在类的初始化阶段执行,内部存在着同步机制。
     
    3.2 将对象的引用保存到volatile类型的域或者AtomicReferance对象中
     
    3.2.1 volatile特性
    • 可见性:对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile变量最后的写入。
    • 原子性:对任意单个 volatile 变量的读/写具有原子性,但类似于 volatile++这种复合操作不具有原子性。
     
    3.2.2 AtomicReferance
     
    3.3 将对象的引用保存到某个正确构造对象的final类型域中
    对于final域,编译器和处理器要遵守两个重排序规则:
    1. 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
    2. 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
    3.4 将对象的引用保存到一个由锁保护的域中
    如:Hashtable、ConcurrentMap、BlockingQueue等容器中。
     
    4 什么是JMM
    Java内存模型(JMM)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见。
     
    4.1 Happens-Before规则
     
    4.1.1 程序顺序规则
    若程序中操作A在操作B之前,则线程中操作A在操作B之前执行。
     
    4.1.2 监视器锁规则
    在同一监视器锁上的解锁操作必须在加锁操作之前执行。
     
    4.1.3 volatile变量规则
    对volatile变量的写操作必须在读操作之前执行。
    StoreStore  volatile写 StoreLoad
    volatile读 LoadLoad LoadStore
     
    4.1.4 线程启动规则
    Thread.start必须在线程中执行的操作之前被调用。
     
    4.1.5 线程关闭规则
    线程中的任何操作必须在其他线程检测到该线程结束之前执行,或者从Thread.join中返回,或调用Threas.isAlive返回false。
     
    4.1.6 中断规则
    当一个线程在另一个线程上调用interrupt时,必须在被中断线程检测到interrupt调用之前执行。
     
    4.1.7 终结器规则
    对象的构造函数必须在启动该对象的终结器之前执行完成。
     
    4.1.8 传递性
    如果操作A在操作B之前执行,操作B在操作C之前执行,则操作A必须在操作C之前执行。
     
    5 防止死锁
     
    5.1 锁顺序
     
    5.2 开放调用
    在不持有锁的情况下调用外部方法。
     
    5.3 tryLock
    支持定时的锁
  • 相关阅读:
    json数据解析转文本方法
    百度HttpV3版本图片识别
    项目用Socket网络框架+Protobuf
    各类数据类型的转换类
    异形按钮点击触发
    通过名字找物体工具
    任意图形工具
    Debug日志可视化
    fread不能读完整个文件
    生产者消费者问题——C++ windows版 多生产者多消费者的队列实现
  • 原文地址:https://www.cnblogs.com/chanedi/p/5142397.html
Copyright © 2011-2022 走看看