synchronized 特性:
1.是可重入锁;
2.锁方法时,锁的是this;
3.锁静态时,锁的是xxx.calss;
4.锁定方法和非锁定方法可以同步执行;
5.异常锁,程序执行中,如果出现异常,默认情况下,锁会被释放;
6.可以保证原子性和可见性。
7.可重入锁,父子类的继承可实现
synchronized 锁升级过程:(只能升级不能降级)
锁对象头部的两位(00:无锁,01:偏向锁,10:自旋锁,11:重量级锁)
1.无锁;
2.偏向锁:
当只有一个线程时,先尝试不对这个线程加锁,只记录这个线程的ID,默认这个对象是这个线程独有的;
3.自旋锁
如果有其他线程来了,就升级为自旋锁。此时占cpu,不经过内核
如果线程锁中已有线程id记录,则后来的线程就会先进行自旋,默认自旋10次,如果依旧拿不到锁,就会升级为重量级锁。
应用:加锁代码执行时间短,并且线程少的情况下,用自旋锁。
4.重量级锁
线程自旋10次后,若还没拿到锁,自旋锁升级为重量级锁-OS锁.
升级为重量级锁后,会进入waitting区,不再占用cpu
应用:加锁代码执行时间长,线程数多时 选用
synchronized使用时需注意:
1.不能用String;
2.不能用Integer;
3.不能用Long;
锁优化
1.锁细化:减少同步代码块
2.锁粗化:线程争用特别频繁时选用
ReentrantLock常用方法:
lock()/unlock() 获得锁,释放锁
tryLock()判断是否可得到锁,返回true/false
lockInteruptibly()可以被打断,对interrupt()做出响应
new ReentrantLock(true)创建公平锁,检查队列中是否有等待的线程,有则进入等待队列
可以通过condition绑定多个条件
synchronized和 ReentrantLock 有什么不同
1.synchronized 是自动加锁解锁的,而 ReentrantLock是需要手动加锁解锁的;
2.sychronized底层实现是锁升级,而ReentrantLock底层实现是cas
3.synchronized 是JVM层面的锁,是Java关键字,而ReentrantLock 是API层面的锁
4.是否可中断:synchronized是不能中断的,除非加锁代码出现异常,或者执行完成才能释放锁,而ReentrantLock 是可以中断的,可通过trylock(long timeout,TimeUnit unit)设置超时方法,或者lockInterruptibly()放到代码块中,调用interrupt方法进行中断。
5.是否公平锁:synchronized是非公平锁,而ReentrantLock 是可以通过构造方法传boolean 值来选择 公平还是非公平,不传则默认非公平。
6.锁是否可绑定多个条件:synchronized不能绑定。ReentrantLock可以通过绑定Condition结合await()/Singal方法实现线程的精确唤醒,而不像synchronized通过Object类的wait()/notify()/notifyAll() 要么随机唤醒一个线程要么全部唤醒
7.锁的对象。synchronized锁的是对象,锁是保存在对象头里面的,根据对象头数据来标识是否有线程来获得锁、争抢锁。ReentrantLock 锁的是线程,根据进入的线程和int 类型的state标识锁的获得和争抢。