基本线程同步(七)修改Lock的公平性

简介:

修改Lock的公平性

在ReentrantLock类和 ReentrantReadWriteLock类的构造器中,允许一个名为fair的boolean类型参数,它允许你来控制这些类的行为。默认值为 false,这将启用非公平模式。在这个模式中,当有多个线程正在等待一把锁(ReentrantLock或者 ReentrantReadWriteLock),这个锁必须选择它们中间的一个来获得进入临界区,选择任意一个是没有任何标准的。true值将开启公平 模式。在这个模式中,当有多个线程正在等待一把锁(ReentrantLock或者ReentrantReadWriteLock),这个锁必须选择它们 中间的一个来获得进入临界区,它将选择等待时间最长的线程。考虑到之前解释的行为只是使用lock()和unlock()方法。由于tryLock()方 法并不会使线程进入睡眠,即使Lock接口正在被使用,这个公平属性并不会影响它的功能。

在这个指南中,我们将修改使用Lock同步代码块食谱示例来使用这个属性,并且观察公平与非公平模式之间的差别。

准备工作…

我们将要修改使用Lock同步代码块食谱的示例,所以阅读那个食谱来实现这个示例。

如何做…

按以下步骤来实现的这个例子:

1.实现有使用Lock同步代码块食谱中解释的示例。

2.在PrintQueue类,修改Lock对象的构造,如下:


1 private Lock queueLock=new ReentrantLock(true);

3.修改printJob()方法,使用两个代码块分离打印的模拟,在它们之间释放锁。


01 public void printJob(Object document){
02 queueLock.lock();
03 try {
04 Long duration=(long)(Math.random()*10000);
05 System.out.println(Thread.currentThread().getName()+":
06 PrintQueue: Printing a Job during "+(duration/1000)+" seconds");
07 Thread.sleep(duration);
08 } catch (InterruptedException e) {
09 e.printStackTrace();
10 } finally {
11 queueLock.unlock();
12 }
13 queueLock.lock();
14 try {
15 Long duration=(long)(Math.random()*10000);
16 System.out.println(Thread.currentThread().getName()+":
17 PrintQueue: Printing a Job during "+(duration/1000)+" seconds");
18 Thread.sleep(duration);
19 } catch (InterruptedException e) {
20 e.printStackTrace();
21 } finally {
22 queueLock.unlock();
23 }
24 }

4.修改Main类中,启动线程的代码块。新的代码块如下:


1 for (int i=0; i<10; i++){
2 thread[i].start();
3 try {
4 Thread.sleep(100);
5 } catch (InterruptedException e) {
6 e.printStackTrace();
7 }
8 }

它是如何工作的…

在以下截图中,你可以看到执行这个例子的一个部分输出:

6

所有线程都创建一个0.1秒的差异,第一需要获取锁的控制权的线程是Thread0,然后是Thread1,以此类推。当Thread0正在运行第一个由锁 保护的代码块时,有9个线程正在那个代码块上等待执行。当Thread0释放锁,它需要马上再次获取锁,所以我们有10个线程试图获取这个锁。当启用代码 模式,Lock接口将会选择Thread1,它是在这个锁上等待最长时间的线程。然后,选择Thread2,然后是Thread3,以此类推。直到所有线 程都通过了这个锁保护的第一个代码块,否则,没有一个线程能执行该锁保护的第二个代码块。

一旦所有线程已经执行完由这个锁保护的第一个代码块,再次轮到Thread0。然后,轮到Thread1,以此类推。

为了看与非公平模式的差异,改变传入锁构造器的参数,传入false值。在以下截图中,你可以看到修改示例后的执行结果:

7

在这种情况下,线程按被创建的顺序执行,但每个线程各自执行两个受保护的代码块。然而,这种行为的原因是没有保证的,正如之前解释的,这个锁将选择任意一个线程获得访问保护代码块。在这种情况下,JVM不能保证线程的执行顺序。

不止这些…

读/写锁在它们的构造器中也有公平参数。这个参数在这种锁中的行为与本指南的解释是一样的。

参见

  • 在第2章,基本线程同步中使用Lock同步代码块的指南
  • 在第2章,基本线程同步中使用读/写锁同步数据访问的指南
  • 在第7章,制订并发类中实现一个自定义的Lock类的指南
目录
相关文章
|
22天前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
54 5
|
3月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
【6月更文挑战第20天】在Java多线程编程中,`synchronized`和`Lock`是两种关键的同步机制。`synchronized`作为内置关键字提供基础同步,简单但可能不够灵活;而`Lock`接口自Java 5引入,提供更复杂的控制和优化性能的选项。在低竞争场景下,`synchronized`性能可能更好,但在高并发或需要精细控制时,`Lock`(如`ReentrantLock`)更具优势。选择哪种取决于具体需求和场景,理解两者机制至关重要。
37 1
|
3月前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
52 0
|
3月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
【6月更文挑战第20天】Java多线程同步始于`synchronized`关键字,保证单线程访问共享资源,但为应对复杂场景,`Lock`接口(如`ReentrantLock`)提供了更细粒度控制,包括可重入、公平性及中断等待。通过实战比较两者在高并发下的性能,了解其应用场景。不断学习如`Semaphore`等工具并实践,能提升多线程编程能力。从同步起点到专家之路,每次实战都是进步的阶梯。
39 0
|
1月前
|
算法 Java
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
该博客文章综合介绍了Java并发编程的基础知识,包括线程与进程的区别、并发与并行的概念、线程的生命周期状态、`sleep`与`wait`方法的差异、`Lock`接口及其实现类与`synchronized`关键字的对比,以及生产者和消费者问题的解决方案和使用`Condition`对象替代`synchronized`关键字的方法。
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
|
22天前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
78 5
|
22天前
|
Java 开发者
揭秘!为什么大神都爱用Lock接口处理线程同步?
揭秘!为什么大神都爱用Lock接口处理线程同步?
37 5
|
22天前
|
Java
在Java多线程领域,精通Lock接口是成为高手的关键。
在Java多线程领域,精通Lock接口是成为高手的关键。相较于传统的`synchronized`,Lock接口自Java 5.0起提供了更灵活的线程同步机制,包括可中断等待、超时等待及公平锁选择等高级功能。本文通过实战演练介绍Lock接口的核心实现——ReentrantLock,并演示如何使用Condition进行精确线程控制,帮助你掌握这一武林秘籍,成为Java多线程领域的盟主。示例代码展示了ReentrantLock的基本用法及Condition在生产者-消费者模式中的应用,助你提升程序效率和稳定性。
18 2
|
22天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
18 2
|
22天前
|
Java
多线程同步新姿势:Lock接口助你“一统江湖”!
多线程同步新姿势:Lock接口助你“一统江湖”!
38 2