线程安全以及实现方式

线程安全程度
从java语言中各种操作共享数据来分,按照线程安全强度来分:
  • 不可变
  • 绝对线程安全
  • 相对线程安全
  • 线程兼容
  • 线程对立
 
不可变
final带来的可见性使得一个不可变变量创建出来(没有使用this引用逃逸出来),永远不会在多个线程中看到它不一致的状态。
final修饰的基本数据类型,对于复杂类型,需要定义其内部的变量为final(String,基本类型的对象类型)
 
绝对线程安全
在java api定义的线程安全的类,大多数不是绝对线程安全。
 
 
相对线程安全
相对线程安全就是我们通常说的线程安全,java api大多数的线程安全类都是属于这种类型。Vector 、HashTable、Collections中的SynchronizedCollection()方法
 
线程兼容
线程兼容指对象本身不是线程安全的,但是可以通过同步手段来保证对象在并发环境下安全的使用。例如 ArrayList、HashMap
 
线程对立
不管是否采用了同步措施,都不能在并发环境下使用的代码。例如 Thread的suspend()和resume()方法。
 
 
线程安全实现方式 
 
1、互斥同步
Synchronized关键字
Synchronized经过编译之后,会在同步块前后加上两条 monitorenter 和 monitorexit 字节码指令。这两个字节码都需要一个reference类型的参数来指明锁对象,如果指定了一个对象,则是这个对象的reference,如果是实例方法或者静态方法,则分别是对象的实例(this) 或者 类的class对象
 
根据规范要求,在执行monitorenter指令,首先尝试去获取对象的锁,如果这个对象没有被锁定或者当前线程已经获取到锁,则锁的计数器+1,执行monitorexit 指令,锁计数器-1,锁释放了。
规范描述有两点:
  • Synchronized同步块对同一个线程是可重入的,不会出现把自己锁死的情况。
  • 同步块在一个执行完之前,会阻塞其他线程进入。
 
Synchronized是java语言中的一个重量级的操作,因为java线程是映射到操作系统的原生线程上的,阻塞或者唤醒一条线程,都需要操作系统来帮忙完成,需要从用户态切换到核心态,转换需要消耗很多处理时间,可能比用户代码执行的时间还长。虚拟机对此作了一些优化,比如 自旋锁,避免频繁进入切换到核心态中。
 
ReentrantLock   重入锁
ReentrantLock  和 Synchronized类似,一个表现为API 层面上的互斥(lock 和 unlock 方法),一个表现为原生语法层面上的互斥。ReentrantLock 比 Synchronized增加了一些高级功能。
  • 等待中断:持有锁的线程长期不释放锁(执行时间长的同步块)的时候,正在等待的线程可以选择放弃等待,做其他事情。
  • 实现公平锁:ReentrantLock 默认是非公平的,通过构造参数可设置为公平锁,Synchronized是非公平的 
  • 锁可以绑定多个条件
 
 
2、非阻塞同步
    互斥同步是一种悲观的同步策略,非阻塞同步是一种乐观同步策略,基于一种冲突检测的策略,就是先进行操作,如果没有冲突,没有其他线程争抢共享数据,那就操作成功,如果存在冲突,则进行其他补救措施(例如常用的 不断的重试,直到成功为止)
 
CAS操作
 
3、无同步方案
    可重入代码
    线程本地存储 ThreadLocal

猜你喜欢

转载自www.cnblogs.com/xiaojianfeng/p/9401704.html
今日推荐