除了都知道的synchronize和volatile的关键字,还有util.concurrent包下的lock接口,一般使用reentrantlock实现类(java1.8之后多加了一个lock的实现类stampedlock,用起来很复杂效果最好),semaphore信号量类,util.concurrent.atomic包下的原子类(这些类都是给util.concurrent包下的工具类使用的,自己写代码要小心使用这些原子类)
volatile实现原理:
当对volatile变量写操作时,会生成一条lock汇编代码生成内存屏障,将cpu缓存中的数据写入内存,并使其他cpu存储了该内存地址的缓存无效。读操作时会强制从内存中读取数据到缓存中,而不直接使用缓存中的数据。jvm的happen before机制保证了在多线程对volatile变量进行读写时,保证是先写后读。因此volatile变量能够在线程间保持可见性,能被多线程同时读,但只能被单线程写。使用volatile能保证多线程安全的读取(这也是concurrenthashmap的get方法高效的原因,因为get方法中只进行读,使用到的域都是volatile的,因此不需要加锁)。
volatile关键字可以实现简单读写的同步也就是轻量级同步(单步的读和写,n=n就不行,这是一个读和一个写两步)
synchronize实现原理:
代码块同步是使用monitorenter和monitorexit实现的(字节码文件中),线程执行到monitorenter时会尝试获取monitor的所有权。
实现大范围的同步。
可重入锁reentrantlock和关键字synchronized比较:
Reentrantlock能完成一切synchronize的的工作,并能额外提供一些功能,可以中断正在试图获得锁的线程、可以设定获得锁的超时时间、一个锁可以有多个条件(newcondition方法获得)、可以设置公平锁(默认是不公平)、解锁必须放在finally块中。
semaphore实现原理:
信号量操作,实例化semaphore来创建有指定数目的许可的对象,acquire方法获得许可,获取不到则阻塞。release方法释放许可。
原子操作和线程同步的关系:
线程同步:本来线程通过调度是不能确保执行顺序的,但是通过一些机制(同步机制),可以使线程按照规律的顺序执行就是同步。同步的作用主要是为了保证共享数据的正确。
原子操作:代码要么全执行要么全不执行,是一个统一的代码块(临界区)。可以分为先天原子操作和后天原子操作。先天的就是对应一句机器码的指令(汇编),后天的是编译器或者操作系统经过处理保证的原子操作。java中除了long和double的基本类型赋值操作时原子的。
原子操作在并发中可以实现同步。
阅读(1732) | 评论(0) | 转发(0) |