-
假如一把锁锁了n个地方,那么只要得到这把锁,那n个地方都可以访问;
-
公平锁是指多个线程按照申请锁的顺序来获取锁,非公平锁性能更高,因为公平锁需要在多核的情况下维护一个队列;
-
ConcurrentHashMap是学习分段锁的最好实践,ConcurrentHashMap默认的并发级别是16,即内部分成了16个HashMap,当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode知道它将放在哪一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行插入;
-
乐观锁适用于读多场景,悲观锁适用于写多场景。乐观锁常见的两种实现方式:版本号机制或CAS算法实现;
-
独占模式下每次只能有一个线程持有锁,属于悲观锁的思想,独占锁限制了并发能力,因为读读操作不需要加锁;
-
共享锁允许多个线程同时获取锁,并发访问共享资源,如ReadWriteLock的读锁是共享锁,共享锁是一种乐观锁思想;
-
尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU;
-
synchronized锁是一个内置关键字,synchronized更加简单;而ReentrantLock是一个Java类,提供了丰富的API,使用起来更加灵活;
-
synchronized有一个锁升级的过程:无锁->偏向锁->轻量级锁(CAS加锁)->膨胀为重量级锁;
-
synchronized自动释放锁(代码执行完或发生异常),ReentrantLock需要手动释放锁
-
synchronized是非公平锁,synchronized可公平可不公平
-
synchronized通过Object类的wait和notify方法实现线程同步,ReentrantLock通过条件变量Condition实现线程同步;
-
synchronized不可中断,ReentrantLock可中断;
-
两者都可重入;
-
两者都是独占锁、悲观锁思想;
-
synchronized适用于少量代码的同步问题,ReentrantLock适用于大量代码的同步问题;
-
资源竞争不激烈时synchronized性能要略优于ReentrantLock;资源竞争激烈时,ReentrantLock性能要优与ReentrantLock;
-
synchronized经历了各种优化,性能已经和ReentrantLock差不多了;
-
非阻塞尝试获取锁tryLock()
-
获取可被中断的锁lockInterruptibly()
-
设置超时时间尝试获取锁tryLock(long, TimeUnit)
Lock接口的完整方法如下:
-
lock():获得锁,如果获取不到就阻塞,获取得到就立即返回,不能被打断;
-
void lockInterruptibly():与lock方法基本一样,但是可以被interrupt打断;
-
Condition newCondition():返回一个新Condition绑定到该Lock实例;
-
boolean tryLock():会立即返回true或false,注意,该方法会获取锁;
-
boolean tryLock(long time, TimeUnit unit):与无参的tryLock方法一样,只不过多了一个超时时间;
-
void unlock():释放锁;
-
lock方法要写在try-catch块外面。lock方法与try之间不要有代码,如果中间有代码且抛出异常,则会导致无法释放锁;
public class ReentrantLockTest {
private int count;
private ReentrantLock reentrantLock = new ReentrantLock();
public void addByLock(){
reentrantLock.lock();
try {
count++;
}finally {
reentrantLock.unlock();
}
}
public void addByTryLock() {
// 拿不到锁就自旋
while (!reentrantLock.tryLock()){
}
try {
count++;
}finally {
reentrantLock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockTest rlt = new ReentrantLockTest();
for (int i = 0; i < 1000000; i++) {
new Thread(()->{
rlt.addByTryLock();
}).start();
}
Runtime.getRuntime().addShutdownHook(new Thread(()->{
System.out.println(rlt.count);
}));
}
}
原文始发于微信公众号(初心JAVA):并发第八弹 ReentrantLock与synchronized的比较
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35531.html