主要分乐观锁和悲观锁。
悲观锁:悲观思想,认为写操作频繁,所以每次读写都会上锁。sycchronized就是悲观锁的一种实现,同时也是一种重量级锁。
乐观锁:乐观思想,认为读多写少(并发写的可能性低),所以不上锁。每次更新前读取版本号,并比较版本号,如果一致则认为没有其他线程的写操作而完成更新,若版本号不一致则放弃此次更新,并重复此次更新(读版本号,比较,更新)操作。
java的乐观锁主要靠volatile和CAS(compare and swap)实现,CAS有内存值V,旧预期值A,新改变值B。如果旧预期值A等于内存值V,则将新改变值赋值给V。–和版本号实现是一个道理。
自旋锁,轻量级锁,偏向锁都是乐观锁的实现。
公平锁和非公平锁:公平锁就是哪个线程先运行就可以先得到锁;非公平锁不管哪个线程先运行,获取锁的线程都是随机的。
关于公平锁和非公平锁的性能:当持有锁的相对时间较长或请求锁的平均间隔时间较长,插队(线程利用等待线程挂起和恢复之间的延迟抢到锁执行并释放锁,即完成了操作同时并不影响被挂起线程恢复之后的使用)不能带来吞吐量的提升,这时应该采用公平锁。反之采用非公平锁,ReentrantLock,synchronized都是非公平锁。
自旋锁:如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
但是线程自旋是需要消耗cup的,说白了就是让cup在做无用功,如果一直获取不到锁,那线程也不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。
如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。
偏向锁(Biased Locking):会偏向于第一个访问锁的线程,如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用的情况,则线程是不需要触发同步的,这种情况下,就会给线程加一个偏向锁。
如果在运行过程中,遇到了其他线程抢占锁,则持有偏向锁的线程会被挂起,JVM会消除它身上的偏向锁,将锁恢复到标准的轻量级锁。
轻量级锁:轻量级锁是由偏向所升级来的,偏向锁运行在一个线程进入同步块的情况下,当第二个线程加入锁争用的时候,偏向锁就会升级为轻量级锁。
synchronized:java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
1:普通同步方法,锁是当前实例对象 2:静态同步方法,锁是当前类的class对象 3:同步方法快,锁是括号里的对象