目录
1.synchronized 和 lock的区别
-
synchronized是一个关键字, lock是一个接口,实际使用的是实现类
-
synchronized通过触发的是系统级别的锁机制, lock是API级别的锁机制
synchronized自动获得锁,自动释放锁。 lock需要通过方法获得锁并释放锁
-
synchronized可以修饰代码段和方法,lock只能修饰代码中
-
synchronized无法判断是否获得锁,lock可以通过tryLock判断
-
synchronized一旦阻塞无法中断,lock可以被中断
lock.lockInterruptibly();等待并可以被中断
-
synchronized一旦出现死锁无法自动解决,lock出现死锁后自动解除
-
synchronized锁的形式单一, lock锁的形式多样化(可重入锁,排他锁,共享锁,读写锁,公平锁,非公平锁)
-
synchronized早先属于重量级锁,性能较低。 lock相比之下性能略高
2.synchronized
2.1用户态与内核态
-
可以理解成是两种对系统元件不同的访问权限
-
程序运行时,会用到很多系统的元件。
-
不是所有的元件,所有的程序都具有使用权限
-
有些元件普通程序(Java程序)就可以直接访问,此时我们就说程序处于用户态
-
有些元件普通不能直接访问,需要通过系统帮助访问(CPU, IO等),此时我们就说程序处于内核态
-
我们的在运行的过程中,随着需要使用的系统元件不同,有可能会从用户态切换到内核态
-
用户态与内核态的切换需要耗时,耗资源。
2.2用户线程与内核线程
-
系统有自己的线程,称为内核线程
-
我们使用Java语言创建的线程(Thread),称为用户线程
-
内核线程的数量与系统的cpu数量(逻辑处理器数量)是相同
-
用户线程在执行过程中,不是直接抢占CPU,而是要争抢与内核线程的关联(映射)
-
如果创建的用户线程过多, 多个用户线程会映射到一个内核线程上
-
但一个内核线程每次(一个时间片)只能为一个用户线程执行任务
-
所以当内核线程在多个用户线程之间切换时,需要保留上一个线程执行的相关信息
-
我们称这个过程为上下文切换
-
上下文切换耗时,耗资源
2.3synchronized重量级锁
-
synchronized在上锁时,最终使用的是系统级别的mutex互斥锁(排他锁)
-
使用synchronized上锁时,会存在用户态与内核态的切换,性能较低。
-
我们称这种会涉及到系统资源使用的锁,为重量级锁。
-
jdk1.5 推出JUC之后, lock锁在一定程度上,减缓了重量级的性能消耗
-
lock锁在整个锁应用过程中,有一部分是在用户态完成的,少量在内核态完成。
-
所以lock在整体性能上要优于synchronized锁。
2.4synchronized锁升级
-
早先版本(1.6-) , synchronized属于重量级锁,因为他直接使用系统级别的互斥锁
-
所以1.5版本的juc中,lock对于synchronized有所优化
-
1.6 直接对synchronized做了优化 , 提供了锁升级的机制
-
升级过程
3.Lock锁不同的锁形式
3.1可重入锁
-
synchronized就是一个可重入锁
-
使用lock时,常用的ReentryLock就是可重入锁
-
当一个线程在获得a对象锁之后,可以继续重复获得对象锁
-
代码形式就是 线程调用同步代码段,在没有执行完毕前,又调用了该对象的另一个同步代码段
注意:
-
针对于Lock锁,加锁的数量和释放锁的数量应该保持相同。
-
否则会产生死锁。
synchronized 和 lock都可能会产生死锁:
-
synchronized 两个线程同时需要彼此所占有的资源
-
lock最常见的死锁情况,就是获得锁后忘释放了。
3.2公平锁和非公平锁
-
synchronized 属于非公平锁
-
Lock之ReentryLock创建锁对象时,可以通过传参指定公平或非公平。默认是非公平锁
当线程1释放锁的同时,又来了一个新线程要想要争抢锁
-
这个新线程,直接存于锁的争抢, 就称非公平锁
-
这个新线程,直接进入同步队列,等待前面的线程释放锁。 就称公平锁
3.3排他锁和共享锁
-
排它锁又称为 互斥锁,也称为 独享锁,当一个线程获得该锁, 其他线程无法获得锁,需要等待
-
synchronized就是一个排它锁
-
Lock中提供了不同的实现
-
-
共享锁, 多个线程可以同时获得这个锁。
-
在Lock应用当中,有一个读写锁,就是对排它锁和共享锁的使用
-
读写就是 共享锁
-
写锁就是 排它锁
-
-
两个线程可以同时获得读锁
-
两个线程只能有一个获得写锁,另一个等待
-
一个线程获得读锁, 另一个线程尝试获得写锁会失败,进入等待状态。
-
一个线程获得写锁, 另一个线程尝试获得读锁会失败,进入等待状态