Lock和synchronized的区别和使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wlddhj/article/details/83791248

Lock和synchronized的区别和使用

同步的三个特性:原子性、可见性、有序性

synchronized

没办法手动释放锁,正因为这样,有可能会导致死锁

加锁的三个位置:

  • 实例方法,以当前实例对象为锁
  • 静态方法,以当前class为锁
  • 代码块,指定锁对象

java虚拟机对Synchronized的优化

锁的状态分四种:无锁状态、偏向锁、轻量级锁、重量级锁

随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级到重量级锁。锁的升级是单向的,只能升级不能降级

Lock

原理:改变内存中state属性的值(1已锁,0未锁)

jdk1.5之后新增的接口,有三个实现类ReentrantLock,以及ReentrantReadWriteLock里面的两个内部类,ReadLock和WriteLock

  • 可以手动控制加锁和释放锁的位置
  • 可以设置锁等待的时间
  • 可以中断等待过程中的锁

ReentrantLock

可重入锁

ReentrantReadWriteLock

可以获取读锁和写锁,也是可重入锁

如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。

如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁

Condition条件

Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的这些方法是和同步锁捆绑使用的;而Condition是需要与互斥锁/共享锁捆绑使用的。

Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。

例如,假如多线程读/写同一个缓冲区:当向缓冲区中写入数据之后,唤醒"读线程";当从缓冲区读出数据之后,唤醒"写线程";并且当缓冲区满的时候,"写线程"需要等待;当缓冲区为空时,"读线程"需要等待。

如果采用Object类中的wait(), notify(), notifyAll()实现该缓冲区,当向缓冲区写入数据之后需要唤醒"读线程"时,不可能通过notify()或notifyAll()明确的指定唤醒"读线程",而只能通过notifyAll唤醒所有线程(但是notifyAll无法区分唤醒的线程是读线程,还是写线程)。 但是,通过Condition,就能明确的指定唤醒读线程。

CAS

比较设置
compareAndSetState

公平锁与非公平锁

Lock可以设置公平锁/非公平锁,synchronized是非公平锁

可重入锁

一个线程内,如果多次遇到需要获取锁的请求,只要第一次获取锁就可以,后续可直接进入,只到释放锁

ReentrantLock和synchronized都是可重入锁

volatile 和 automatic

volatile禁止CPU对指令重排序,保证了指令有序性,但是不能保证自增时的原子性

automatic在volatile基础上再封装了一层,保证了操作的原子性,增加了内存屏障

参考资料

展开阅读全文

没有更多推荐了,返回首页