synchronized 和 volatile 有什么区别
两个关键字是互补的存在
- volatile 关键字是线程同步的轻量级实现,所以volatile性能好一些。但是 volatile 关键字只能用于变量 而 synchronized 关键字可以修饰方法以及代码块
- volatile 关键字能保证数据的可见性,不能保证原子性。synchronized 关键字两者都能保证
- volatile 关键字主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字解决的是多个线程之间访问资源的同步性
ReentrantLock 关键字
ReentrantLock 是什么
ReentrantLock 实现了 Lock 接口,是一个可重入且可独占式的锁,和 synchronized 关键字类似。不过,ReentrantLock 更灵活强大,增加了轮询、超时、中断、公平锁和非公平锁等高级功能
ReentrantLock 底层是 AQS 实现的,因为里面有一个内部类 Sync,Sync 继承 AQS,添加锁和释放锁大部分操作都是在 Sync 中实现。
Sync 有公平锁 FairSync 和非公平锁 NonfairSync,ReentrantLock 默认使用非公平锁
公平锁和非公平锁区别:
- **公平锁:**锁被释放之后,先申请的线程先得到锁。性能较差,因为公平锁为了保证时间上的绝对顺序,上下文切换频繁。
- **非公平锁:**锁被释放之后,后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但是可能会导致某些线程永远无法获取到锁
synchronized 和 Lock 区别
lock通常是java.util.concurrent.locks包下的接口,如ReentrantLock是其实现类之一。
机制:
synchronized:是Java语言内置的同步机制,基于JVM的内置锁实现。
lock:是Java提供的显式锁机制,需要手动获取和释放锁。
灵活性:
synchronized:灵活性相对较低,只能用于方法或代码块。
lock:提供了更多的灵活性,例如可以尝试获取锁、可中断获取锁、可设置锁的公平性等。
等待与通知:
synchronized:与wait()和notify()/notifyAll()方法一起使用,用于线程的等待和通知。
lock:可以与Condition接口结合,实现更细粒度的线程等待和通知机制。
synchronized 和 ReentranLock 区别
- 两者都是可重入锁
可重入锁:也叫递归锁,指的是线程可以再次获取自己的内部锁。比如一个线程获得了某个还没有释放锁的对象的锁,当再次获取该对象的锁的时候还是可以获取的,如果是不可重入锁的话就会造成死锁
-
synchronized 依赖于 JVM 而 ReentranLock 依赖于 API
synchronized 依赖于 JVM 实现的,都是在虚拟机层面实现的,没有直接暴露给我们
ReentrantLock 是 JDK 层面实现的,也就是 API面,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成,所以我们是可以通过查看它的源代码看到它是如何实现的
-
ReentranLock 比 synchronized 增加了一些高级功能
-
等待可中断:
用 lock.lockInterruptibly() 来实现这个机制
-
可实现公平锁:
ReentrantLock 类的 ReentranLock(boolean fair) 指定是否是公平的
synchronized 只能是非公平锁
-
可实现选择性通知(锁可以绑定多个条件)
ReentrantLock 类可以结合 Condition 实例可以实现选择性通知,
Condition 实例的 signalAll() 方法,只会唤醒注册在该 Condition 实例中的所有等待线程,如果执行 synchronized 的 notifyAll() 方法的话就会通知所有处于等待状态的线程,这样会造成很大的效率问题。
总的来说,synchronized是Java中内置的、简单易用的线程同步机制,适用于大多数情况下的线程同步;而ReentrantLock是更灵活、功能更强大的线程同步机制,适用于一些特殊的需求场景。
可中断锁和不可中断锁有什么区别
- 可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后 才能进行其他逻辑处理。ReentranLock
- 不可中断锁:一旦申请了锁,就只能等到拿到锁以后再能进行其他逻辑处理。synchronized
明天会更新我 Redis 的缓存策略,记得来看!!!