voliate 赋予变量在多线程中的可见性,只能作用于变量,非堵塞。java内存模型(如下图)描述了多线程之间信息交换和同步的方式:每个线程都从主内存load一份数据到自己的工作内存,线程对变量的读写操作都是在工作内存中进行的,然后在save到主内存。
如果多线程同时操作主内存同意拷贝变量a,那么就可能导致变量的值乱掉,voliate 保证了voliate 变量值修改后的新值立即同步到主内存,每次使用变量也都从主内存刷新数据,即保证了数据在线程间的可见性以及禁止指令重排序。
synchronize通过加锁堵塞的方式来实现同步,可以修饰变量,方法以及代码块。https://blog.csdn.net/u013795543/article/details/83716108
AtomicInteger的本质:自旋锁+Unsafe的CAS原子操作,非堵塞同步方式(同步指的是一直等待结果,非堵塞是指可以做其他的事情,并不释放cpu资源。)。
网上的一则故事比较生动地讲堵塞与同步
故事:老王烧开水。 出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。 老王想了想,有好几种等待方式 1.老王用水壶煮水,并且站在那里,不管水开没开,每隔一定时间看看水开了没。-同步阻塞 老王想了想,这种方法不够聪明。 2.老王还是用水壶煮水,不再傻傻的站在那里看水开,跑去寝室上网,但是还是会每隔一段时间过来看看水开了没有,水没有开就走人。-同步非阻塞 老王想了想,现在的方法聪明了些,但是还是不够好。 3.老王这次使用高大上的响水壶来煮水,站在那里,但是不会再每隔一段时间去看水开,而是等水开了,水壶会自动的通知他。-异步阻塞 老王想了想,不会呀,既然水壶可以通知我,那我为什么还要傻傻的站在那里等呢,嗯,得换个方法。 4.老王还是使用响水壶煮水,跑到客厅上网去,等着响水壶自己把水煮熟了以后通知他。-异步非阻塞 老王豁然,这下感觉轻松了很多。对于互斥锁这样的悲观锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁是乐观锁,它不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
优点:通过CAS保证了原子性
缺点:消耗CPU性能
重入锁底层实现是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; }