一、voliatejava
voliate赋予变量在多线程中的可见性,只能做用于变量,非堵塞。java内存模型(以下图)描述了多线程之间信息交换和同步的方式:每一个线程都从主内存load一份数据到本身的工做内存,线程对变量的读写操做都是在工做内存中进行的,而后在save到主内存。bash
若是多线程同时操做主内存赞成拷贝变量a,那么就可能致使变量的值乱掉,voliate保证了voliate变量值修改后的新值当即同步到主内存,每次使用变量也都从主内存刷新数据,即保证了数据在线程间的可见性以及禁止指令重排序。多线程
二、synchronized异步
synchronize经过加锁堵塞的方式来实现同步,能够修饰变量,方法以及代码块.性能
Synchronized 的语义底层是经过一个 Monitor 的对象来完成,ui
每一个对象有一个监视器锁(Monitor),当 Monitor 被占用时就会处于锁定状态。 线程执行 Monitorenter 指令时尝试获取 Monitor 的全部权,过程以下: 若是 Monitor 的进入数为 0,则该线程进入 Monitor,而后将进入数设置为 1,该线程即为 Monitor 的全部者。spa
若是线程已经占有该 Monitor,只是从新进入,则进入 Monitor 的进入数加 1。线程
若是其余线程已经占用了 Monitor,则该线程进入阻塞状态,直到 Monitor 的进入数为 0,再从新尝试获取 Monitor 的全部权。code
执行 Monitorexit 的线程必须是 Objectref 所对应的 Monitor 的全部者。 指令执行时,Monitor 的进入数减 1,若是减 1 后进入数为 0,那线程退出 Monitor,再也不是这个 Monitor 的全部者orm
三、AtomicInteger
AtomicInteger的本质:自旋锁+Unsafe的CAS原子操做,非堵塞同步方式(同步指的是一直等待结果,非堵塞是指能够作其余的事情,并不释放cpu资源。)。
网上的一则故事比较生动地讲堵塞与同步
故事:老王烧开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
老王想了想,有好几种等待方式
1.老王用水壶煮水,而且站在那里,无论水开没开,每隔必定时间看看水开了没。-同步阻塞
老王想了想,这种方法不够聪明。
2.老王仍是用水壶煮水,再也不傻傻的站在那里看水开,跑去寝室上网,可是仍是会每隔一段时间过来看看水开了没有,水没有开就走人。-同步非阻塞
老王想了想,如今的方法聪明了些,可是仍是不够好。
3.老王此次使用高大上的响水壶来煮水,站在那里,可是不会再每隔一段时间去看水开,而是等水开了,水壶会自动的通知他。-异步阻塞
老王想了想,不会呀,既然水壶能够通知我,那我为何还要傻傻的站在那里等呢,嗯,得换个方法。
4.老王仍是使用响水壶煮水,跑到客厅上网去,等着响水壶本身把水煮熟了之后通知他。-异步非阻塞
老王豁然,这下感受轻松了不少。
对于互斥锁这样的悲观锁,若是资源已经被占用,资源申请者只能进入睡眠状态。可是自旋锁是乐观锁,它不会引发调用者睡眠,若是自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是所以而得名。
复制代码
优势:经过CAS保证了原子性
缺点:消耗CPU性能
四、ReentrantLock
重入锁底层实现是AbstractQueuedSynchronizer,简称AQS。synchronized是基于JVM层面实现的,而Lock是基于JDK层面实现的。相比synchronized,ReentrantLock能够进行锁的超时和中断设置。重入性是指若是以获取锁的线程再次去获取锁,那么就会获取锁成功,获取锁成功次数加1,后面释放锁锁的次数必须等于以前成所获取锁的的次数,那么该锁才算彻底释放。
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) { //获取锁
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //锁是否被占用
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //占用锁的线程是否时当前线程
int nextc = c + acquires; //若是是,则获取锁次数+1
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) { //释放锁
int c = getState() - releases; //上辈子造的孽,一个个减吧
if (Thread.currentThread() != getExclusiveOwnerThread()) //占用锁的线程是否时当前线程
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true; //真正释放了
setExclusiveOwnerThread(null); //真正释放了
}
setState(c);
return free;
}
复制代码