synchronized详解 乐观锁和悲观锁 volatile关键字 无锁编程CAS CPU锁类型
- 2016-05-19 20:54:00
- admin
- 原创 1341
一、synchronized详解
1、synchronized(obj)锁对象是obj,相当于互斥锁,只有一个线程可以访问;
2、synchronized修饰方法相当于synchronized(this),比如public synchronized void method();
3、synchronized修饰静态方法时锁对象是类;
4、synchronized操作无法被中断,除非获取到锁;
5、synchronized是重入锁,持有锁的线程可以访问其它同步方法;
6、synchronized是非公平锁,多个线程同时获取锁,获取到锁的顺序不保证;
7、示例代码:Syncn.java
public class Syncn {
public void run1() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public void run2() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
final Syncn syncn = new Syncn();
Thread a = new Thread(new Runnable(){public void run() {syncn.run1();}}, "a");
Thread b = new Thread(new Runnable(){public void run() {syncn.run2();}}, "b");
a.start();
b.start();
}
}
二、乐观锁和悲观锁
独占锁是一种悲观锁,synchronized是一种独占锁,只有确保其它线程不会造成干扰的情况下执行,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁;而更加有效的锁就是乐观锁,乐观锁每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
三、volatile关键字
1、C或者C++禁止编译器优化volatile修饰的变量,每次访问都直接重内存读取,不使用寄存器;
2、JAVA禁止编译器优化volatile修饰的变量,每次访问直接从堆内存读取,不使用线程变量副本;
3、示例:C语言volatile int value,JAVA语言private volatile int value;
四、无锁编程CAS
1、CAS:Compare and Swap,中文意思是"比较并交换";
2、java.util.concurrent包中借助CAS实现了区别于synchronized同步锁的一种乐观锁;
3、无锁编程只保证单个读和写操作的原子性,并不保证组合操作的原子性;
硬件支持CAS,LL/SC, atom read-modify-write:
如果CPU提供了Load-Link/Store-Conditional这对指令,则就可以轻松实现变量的CPU级别无锁同步;
LL [addr],dst:从内存[addr]处读取值到dst;
SC value,[addr]:对于当前线程,自从上次的LL动作后内存值没有改变,就更新成新值;
软件实现CAS,CPU没有实现LL/SC这对指令,那么就需要寻找软件算法,比如CAS。
CAS缺陷1,ABA问题(JAVA的AtomicStampedReference可以解决此问题):
线程A执行cas(1,2),还没执行完成就被抢占;
线程B执行cas(1,2),cas(2,1);
线程A继续执行,发现条件成立执行成功,但实际上值中间已经被修改过;
CAS缺陷2,循环时间长开销大。
CAS缺陷3,只能保证一个共享变量的原子操作(AtomicReference可以解决此问题)。
五、CPU锁类型
1、基本操作的原子性,单处理器对同一缓存行的16/32/64位操作是原子操作;
2、总线锁机制,处理器之间访问一块共享内存时顺序执行,先到的CPU先执行,后到的CPU被阻塞;
3、缓存锁机制,比总线锁开销小,但使用场景受限;