并发编程中的各种锁

1.  内置锁

  synchronized,这个不用说了,作用就是实现互斥之外,还有内存可见性,复合操作原子性等作用;一个线程拥有某个对象的synchronized锁,该线程调用wait方法后,会释放对象的锁;

2.  ReentrantLock

  ReentrantLock和synchronized在并发性和内存语义方面都相同,但是又多了锁投票,定时锁等候和中断锁等候

  线程A和B都想获得对象O的锁,A获得锁后,如果是synchronized,线程B会一直等待直到获得锁为止;

  而ReentrantLock会等待一段时间后停止等待;

  ReentrantLock获得锁的三种方式

  lock()方法:如果获得了锁,立即返回,否则处于休眠状态,直到获得锁为止;

  tryLock()方法:如果获得了锁,返回true,否则,返回false;

  tryLock(long timeout, TimeUnit unit): 等待timeout时间后还没有获得锁,则返回false,否则,返回true;

  lockInterruptibly():如果获得了锁,立即返回;如果没有获得锁,该线程处于休眠状态直到获得锁,或者该线程被中断;

  newCondition():作用和synchronized里的wait/notify方法很像;

  Condition里面的await()方法和synchronized的wait()方法一样,Condition的signal()和notify()方法类似;

  ReentrantLock和synchronized的区别:synchronized是在JVM层面实现的,当运行出错时,JVM会自动终止程序运行;而ReentrantLock是在JDK层面上实现的,需要手动释放锁,最后要在finally里手动释放;

  结论:synchronized在竞争不是很激烈的时候适合使用,性能比ReentrantLock好一点点;但是竞争很激烈时,synchronized性能下降很厉害,而ReentrantLock能保持不变。

 3.  自旋锁

  3.1  为什么会出现自旋锁?

  操作系统CPU进行线程的上下文替换需要时间比较长,所以我们想办法减少线程的上下文切换次数;自旋锁一般用于多处理器,线程A、B在不同的处理器上被执行,且都需要对象O的锁,现在O的锁被B占着,A请求O的锁,A不会进入阻塞状态,而是执行空循环等待B释放O的锁。

  3.1  使用场景?  

  可知,如果B占用O很短,那么自旋锁效率很高,如果B会占用很长时间,或者该锁竞争激烈,效果不好。

  

原文地址:https://www.cnblogs.com/zhihuayun/p/7337870.html