java 线程安全的实现方式

线程安全的定义:

<<Java Concurrency In Practice>>的作者Brian  Goetz 对"线程安全"有一段定义: 当多个线程访问一个对象的时候, 如果不用考虑这些线程在运行时环境下的调度和交替执行, 也不需要惊醒额外的同步,或者在调用方惊醒任何其他的协调操作,调用这个对象的行为都可以获取正确的结果,那这个对象就是线程安全的. 

我们把java中各种操作共享的数据分成一下5类:

不可变, 绝对线程安全, 相对线程安全, 线程兼容, 线程对立.

线程安全的实现方法:

(1) 互斥同步:

互斥是因, 同步是果,推荐使用 synchronized 关键字进行同步, 在 concurrent包中有ReentrantLock类, 实现效果差不多. 还是推荐原生态的synchronized.

(2) 非阻塞同步:

需要硬件指令完成.常用的指令有:

Test-and-Set

Fetch-and-Increment

Swap

Compare-and-Swap (CAS)

Load-Linked/Store-Conditional (LL/SC)

典型的应用在 AtomicInteger 中

(3) 无同步方案

可重入代码: 在代码执行的任何时刻中断它, 转而去执行另外一段代码,而在控制权返回后,原来的程序不会出现任何错误.

可重入代码有一些共同的特性: 例如不以来存储在堆上的数据和公用的系统资源,用到的状态量都由参数中传入,不调用非可重入的方法等.

线程本地存储: 如果一段代码中所需要的数据必须与其他代码共享,那就看看这些共享数据的代码是否能保证在统一线程中执行?如果能保证,可以把共享数据的可见范围限制在同一个线程中,这样,无需同步也能保证线程之间不出现数据争用问题. 在java中可以通过使用 java.lang.ThreadLocal 开实现线程本地存储的功能.  

这种应用在人人网的开源框架 Rose 有广泛的应用,最经典的应用在获取当前登录用户对象的时候, 是通过t票 到cache中来拿到当前登录用户的user对象. 对象就保存在 ThreadLocal 中. 经典的web交互模型中"一个请求对应一个服务器线程"的处理方式, 把user对象保存在线程本地存储中 可以很好的解决线程安全的问题.

相关推荐