首页 > 其他分享 >synchronized 和 ReentrantLock的区别

synchronized 和 ReentrantLock的区别

时间:2024-06-23 21:54:09浏览次数:12  
标签:synchronized Thread 区别 lock ReentrantLock 线程 公平

synchronized 和 ReentrantLock的区别

   在讨论synchronized 和 ReentrantLock的区别前,我们先了解一下什么是公平锁和非公平锁

   一、 公平锁和非公平锁

   从公平的角度来说,Java 中的锁总共可分为两类:公平锁和非公平锁。但公平锁和非公平锁有哪些区别?孰优孰劣呢?在 Java 中的应用场景又有哪些呢?接下来我们一起来看。

   1.  定义

   公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁。

   非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁。

   2. 代码演示

   接下来我们使用 ReentrantLock 来演示一下公平锁和非公平锁的执行差异,首先定义一个公平锁,开启 3 个线程,每个线程执行两次加锁和释放锁并打印线程名的操作,

   如下代码所示:

   非公平锁:

 1 public class ReentrantLockFairTest {
 2     static Lock lock = new ReentrantLock();
 3     public static void main(String[] args) throws InterruptedException {
 4         for (int i = 0; i < 3; i++) {
 5             new Thread(() -> {
 6                 for (int j = 0; j < 2; j++) {
 7                     lock.lock();
 8                     try {
 9                         System.out.println("当前线程:" + Thread.currentThread().getName());
10                     } finally {
11                         lock.unlock();
12                     }
13                 }
14             }).start();
15         }
16     }
17 }
18 
19 //执行结果
20 当前线程:Thread-0
21 当前线程:Thread-0
22 当前线程:Thread-1
23 当前线程:Thread-1
24 当前线程:Thread-2
25 当前线程:Thread-2

   公平锁:

 1 public class ReentrantLockUnfairTest {
 2     static Lock lock = new ReentrantLock(true);
 3     public static void main(String[] args) throws InterruptedException {
 4         for (int i = 0; i < 3; i++) {
 5             new Thread(() -> {
 6                 for (int j = 0; j < 2; j++) {
 7                     lock.lock();
 8                     try {
 9                         System.out.println("当前线程:" + Thread.currentThread().getName());
10                     } finally {
11                         lock.unlock();
12                     }
13                 }
14             }).start();
15         }
16     }
17 }
18 
19 //执行结果
20 当前线程:Thread-0
21 当前线程:Thread-1
22 当前线程:Thread-2
23 当前线程:Thread-0
24 当前线程:Thread-1
25 当前线程:Thread-2

    说明:

     从上述结果可以看出,使用公平锁线程获取锁的顺序是:A -> B -> C -> A -> B -> C,也就是按顺序获取锁。而非公平锁,获取锁的顺序是 A -> A -> B -> B -> C -> C,原因是所有线程都争抢锁时,因为当前执行线程处于活跃状态,其他线程属于等待状态(还需要被唤醒),所以当前线程总是会先获取到锁,所以最终获取锁的顺序是:A -> A -> B -> B -> C -> C。

    3. 公平锁和非公平锁有何区别

   公平性是指在竞争场景中,当公平性为真时,会倾向于将锁赋予等待时间最久的线程。公平性是减少线程“饥饿”(个别线程长期等待锁,但始终无法获取)情况发生的一个办法。

   1)公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。

   2)非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。

   看下面代码案例所示:可以得出结论,公平锁指的是哪个线程先运行,那就可以先得到锁。非公平锁是不管线程是否是先运行,新的线程都有可能抢占已经在排队的线程的锁。

   4.  优缺点分析

   公平锁的优点是按序平均分配锁资源,不会出现线程饿死的情况,它的缺点是按序唤醒线程的开销大,执行性能不高。

   非公平锁的优点是执行效率高,谁先获取到锁,锁就属于谁,不会“按资排辈”以及顺序唤醒,但缺点是资源分配随机性强,可能会出现线程饿死的情况。

 

   二、synchronized

   三、ReentrantLock

四、synchronized 和 ReentrantLock的区别

五、总结
在 Java 语言中,锁的默认实现都是非公平锁,原因是非公平锁的效率更高,使用 ReentrantLock 可以手动指定其为公平锁。非公平锁注重的是性能,而公平锁注重的是锁资源的平均分配,所以我们要选择合适的场景来应用二者。

 


在 Java 语言中,锁 synchronized 和 ReentrantLock 默认都是非公平锁,当然我们在创建 ReentrantLock 时,可以手动指定其为公平锁,但 synchronized 只能为非公平锁。

参考链接:
https://www.cnblogs.com/vipstone/p/16248006.html
https://juejin.cn/post/6844903695298068487

 

标签:synchronized,Thread,区别,lock,ReentrantLock,线程,公平
From: https://www.cnblogs.com/hld123/p/18263975

相关文章

  • ecoAddRepeater -loc与-offLoadAtLoc的区别
    我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?拾陆楼知识星球入口 ecoAddRepeater-loc{xy}-cellBUF-netNET ecoAddRepeater-offLoadAtLoc{xy}-cellBUF-netNET 都是指定插buf/inv物理位置,区别在于前者用于插buf/inv驱动原始net所有的inputterm,后......
  • vim编辑器中:wq wq! x q q!的详细区别
    下面的命令只是在vi编辑命令中使用:wq:表示保存退出:wq!:表示强制保存退出:x:表示保存退出:q:在vim中表示退出:q!:表示强制不保存退出,不对文件进行保存:wq和:wq!的区别如下:有些文件设置了只读,一般不是修改文件的,但是如果你是文件的owner或者root的话,通过:wq!还是能保存文件退出如果......
  • bed 文件 和 wig 文件 有什么区别
    BED(BrowserExtensibleData)文件和WIG(Wiggle)文件是两种用于基因组数据存储和展示的常见格式,在浏览基因组数据时这两者用途明显不同。BED文件特点:格式简单:通常每一行代表一个基因组区域,包含的基本列为染色体(chromosome)、起始位置(start)、结束位置(end),此外还可以包括额外的列如......
  • react中useState、useRef、变量之间的区别
    数组件有函数作用域,每次render时,声明的方法会生成新的引用,声明的普通变量会重新声明并赋值初始值,而useRef和useState会保留状态。1.useState组件更新不会改变之前的状态,可以保存状态。值变化,会render,视图会更新,setState是异步的,同一个函数内设置的,不能实时获取到最新的值。使用......
  • 【SQL】varchar 与 char 的区别
    在SQL中,VARCHAR和CHAR是用于存储字符串类型数据的两种数据类型,但它们在存储方式和性能上有显著的区别。CHAR定义:CHAR是一种固定长度的字符串数据类型。长度:你需要在定义表结构时指定长度,例如CHAR(10)。存储方式:无论实际存储的字符串长度是多少,都会占用固定的......
  • 【SQL】in 和 exists 的区别
    在SQL中,IN和EXISTS都用于过滤查询结果,但它们在使用场景和性能方面有一些区别。下面是详细的解释:1.ININ操作符用于检查某个值是否存在于一个指定的列表或子查询的结果集中。IN常用于较小的数据集和静态值列表。语法SELECTcolumn1,column2FROMtable1WHERE......
  • 【大语言模型基础】GPT和GPT2区别
    GPT:参数量:1.17亿个参数。模型架构:采用12层的Transformer编码器架构GPT由pretraining和fine-tuning(SFT)两部分组成trainingobjective:predictthenexttoken做pretraining的好处:语料学习与理解:预训练可以让模型在大量的语料上学习语言的基本规律、词汇的语义、句子的结......
  • java中Optional的应用,以及map和flatMap的区别
    关于Option的介绍可以看深入理解java8中的Optional类就可以了,但是复杂一点的使用在网上却没有搜到,这里结合我开发时遇到的真实案例来讲一下Option的使用。1.案例一在真实业务操作过程中,都是对象里面套对象,这边先简单定义操作对象:publicclassPictureCondition{privateStri......
  • golang runtime.Caller 获取调用堆栈信息, Caller(1) 和 Caller(2) 的区别
     funcwhoCalledMe(){//获取调用堆栈信息_,fileName,lineNo,ok:=runtime.Caller(2)if!ok{fmt.Println("Failedtogetcallerinformation")return}fmt.Printf("Calledfrom:%s:%d\n",fileName,lineNo......
  • 高斯算法的原理及其与常规求和方法的区别
    高斯算法的原理高斯算法的原理源于数学家卡尔·弗里德里希·高斯在他少年时期发现的一种求和方法。当时老师让学生们计算1到100的和,高斯发现了一种快速计算的方法。高斯注意到,如果将序列的首尾两数相加,结果总是相同的。例如:[1+100=101][2+99=101][3+98......