锁( ReentrantLock,Synchronized)

news/2024/5/17 18:15:32 标签: java, , synchronized, Reentrantlock

1.lock和synchronized

  • 语法层面

synchronized 是关键字,源码在 jvm 中,用 c++ 语言实现;

Lock 是接口,源码由 jdk 提供,用 java 语言实现;

使用 synchronized 时,退出同步代码块自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放

  • 功能层面

二者均属于悲观、都具备基本的互斥、同步、重入功能;

Lock 提供了许多 synchronized 不具备的功能,例如公平、可打断、可超时、多条件变量

Lock 有适合不同场景的实现,如 ReentrantLock, ReentrantReadWriteLock(读写)

  • 性能层面

在没有竞争时,synchronized 做了很多优化,如偏向、轻量级,性能不赖

在竞争激烈时,Lock 的实现通常会提供更好的性能

2.ReentrantLock的代码实现

对于ReentrantLock来说,它既可以使用乐观思想,也可以使用悲观思想,具体取决于如何使用它的不同方法。

  1. 悲观思想: 在使用ReentrantLock时,可以使用它的lock()和unlock()方法来实现悲观思想。在使用lock()方法获取之前,它会一直等待直到获取到,如果其他线程已经持有,则当前线程会被阻塞。这种方式与传统的悲观思想相似,它假设并发访问会导致冲突,因此在访问共享资源之前先获取

示例代码:

ReentrantLock lock = new ReentrantLock();
​
lock.lock(); // 获取
try {
    // 访问共享资源
} finally {
    lock.unlock(); // 释放
}
  1. 乐观思想: 在使用ReentrantLock时,可以使用它的tryLock()方法来实现乐观思想。tryLock()方法尝试获取,如果获取成功则返回true,否则返回false,不会一直等待。这种方式与乐观思想相似,它假设并发访问不会导致冲突,因此直接进行操作而不获取

示例代码:

ReentrantLock lock = new ReentrantLock();
​
if (lock.tryLock()) { // 尝试获取
    try {
        // 访问共享资源
    } finally {
        lock.unlock(); // 释放
    }
} else {
    // 被其他线程持有,处理逻辑
}

需要注意的是,ReentrantLock的乐观思想并不是基于CAS机制实现的,而是基于AQS(AbstractQueuedSynchronizer)实现的。因此,它的乐观并不是真正意义上的无操作,而是一种基于线程等待/唤醒机制的乐观策略。

3.ReentrantLock构造原理

ReentrantLock主要利用CAS+AQS队列来实现。它支持公平和非公平,两者的实现类似

构造方法接受一个可选的公平参数(默认非公平),当设置为true时,表示公平,否则为非公平。公平的效率往往没有非公平的效率高,在许多线程访问的情况下,公平表现出较低的吞吐量。

拓展延申

1)AQS

关键时FIFO双向队列和属性state

  • 是多线程中的队列同步器。是一种机制,它是做为一个基础框架使用的,像ReentrantLock、Semaphore都是基于AQS实现的

  • AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程

  • 在AQS内部还有一个属性state,这个state就相当于是一个资源,默认是0(无状态),如果队列中的有一个线程修改成功了state为1,则当前线程就相等于获取了资源

  • 在对state修改的时候使用的cas操作,保证多个线程修改的情况下原子性

2)了解AQS与Synchronized的区别

3)CAS

CAS的全称是: Compare And Swap(比较再交换),它体现的一种乐观的思想,在无情况下保证线程操作共享数据的原子性。

4)乐观与悲观

CAS 是基于乐观的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。

synchronized 是基于悲观的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了你们都别想改,我改完了解开,你们才有机会。

在Java中,synchronized关键字ReentrantLock类都是悲观的实现。

在Java中,Atomic类和CAS(Compare and Swap)机制都是乐观的实现。

4.Java中synchronized的代码实例

下面是Java中使用synchronized关键字的几种代码示例:

  1. 同步方法:

public synchronized void synchronizedMethod() {
    // 同步的代码块
}
  1. 同步代码块:

public void synchronizedBlock() {
    synchronized (this) {
        // 同步的代码块
    }
}
  1. 静态同步方法:

public static synchronized void synchronizedStaticMethod() {
    // 同步的代码块
}
  1. 同步对象

public class MyClass {
    private final Object lock = new Object();
​
    public void synchronizedObjectLock() {
        synchronized (lock) {
            // 同步的代码块
        }
    }
}

在上述示例中,使用synchronized关键字修饰的方法或代码块被称为同步方法或同步代码块,它们保证了同一时刻只能有一个线程访问被同步的代码块。synchronized关键字可以修饰方法、代码块、静态方法,以及指定的对象

当一个线程进入到一个被synchronized修饰的方法或代码块时,它会尝试获取对象的。如果没有被其他线程占用,则该线程获取到并执行同步代码块;如果已经被其他线程占用,则该线程会进入阻塞状态,直到被释放。

需要注意的是,synchronized关键字是可重入的,即一个线程可以多次获取同一个。当一个线程已经获取到时,它可以再次进入被同步修饰的方法或代码块,而不会被阻塞。这种机制可以避免死的发生。

另外,synchronized关键字还可以用于实现线程之间的通信,通过wait()、notify()和notifyAll()方法来实现线程的等待和唤醒操作。这些方法必须在synchronized修饰的代码块中调用,并且是针对同一个对象的操作。

5.说一下无操作?

操作是指在并发编程中,通过使用特定的算法和数据结构,避免使用传统的机制(如互斥、读写等),从而实现对共享资源的并发访问而无需阻塞或等待其他线程释放的操作。

操作通常基于原子操作和CAS(Compare and Swap)机制来实现。CAS是一种乐观思想的实现方式,它通过比较内存中的值与期望值,如果相等则更新为新值,否则不做任何操作。CAS操作是原子性的,可以保证在多线程环境下的一致性。

操作的优点包括:

  1. 减少线程的阻塞和切换开销:无操作不需要等待其他线程释放,避免了线程的阻塞和切换开销,提高了系统的并发性能。

  2. 避免死和饥饿问题:无操作不涉及的竞争和资源的争夺,可以避免死和饥饿问题。

  3. 提高系统的可伸缩性:无操作可以实现更细粒度的并发控制,提高系统的可伸缩性。

然而,无操作也存在一些挑战和限制:

  1. 实现复杂度高:无操作需要使用特定的算法和数据结构,实现起来较为复杂。

  2. 适用场景有限:无操作适用于对共享资源的读操作频繁,写操作较少的场景,对于复杂的写操作,仍然需要使用来保证操作的原子性

  3. ABA问题:由于无操作不需要获取,可能会导致ABA问题,即一个值被修改为另一个值,然后再被修改回原来的值,导致线程无法察觉到值的变化。

总之,无操作是一种高效的并发编程方式,可以提高系统的并发性能和可伸缩性,但需要根据具体场景和需求来选择合适的并发控制策略。


http://www.niftyadmin.cn/n/5000460.html

相关文章

第十八课、Qt 下载、安装与配置

功能描述:介绍了 Qt 的下载、安装和配置的全部过程,并对关键页面选项进行了详细说明 一、Qt 的下载 Qt 官方下载地址:https://www.qt.io/zh-cn/downloadhttps://download.qt.io/https://download.qt.io/https://www.qt.io/zh-cn/download进入…

java八股文面试[多线程]——FutureTask

FutureTask介绍 FutureTask是一个可以取消异步任务的类。FutureTask对Future做的一个基本实现。可以调用方法去开始和取消一个任务。 一般是配合Callable去使用。 异步任务启动之后,可以获取一个绑定当前异步任务的FutureTask。 可以基于FutureTask的方法去取消…

操作系统(OS)与系统进程

操作系统(OS)与系统进程 冯诺依曼体系结构操作系统(Operator System)进程基本概念进程的描述(PCB)查看进程通过系统调用获取进程标示符(PID)通过系统调用创建进程(fork)进程状态&…

leetcode第361场周赛补题

7020. 统计对称整数的数目 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;转化为字符串后枚举 class Solution { public:int countSymmetricIntegers(int low, int high) {int res 0;for(int i low; i < high; i ){string s to_string(i);if(s.size() % 2) …

POJ 2010 Moo University - Financial Aid 二分

一、题目大意 给定N头牛的成绩和花费&#xff0c;从中取出C头牛&#xff08;C为奇数&#xff09;&#xff0c;使得它们的花费不超过F同时中位数最大。 二、解题思路 对中位数的牛的下标进行二分&#xff0c;left选择为N的一半&#xff0c;right选择为所有牛的数量1&#xff…

软件开发模型汇总

1. 软件模型 在计算机刚刚诞生的年代&#xff0c;计算机是一种只有天才才能掌握的工具。人们对计算机的认知仅仅停留在程序的层面上&#xff0c;所谓的软件开发就是这些能够掌握计算机的天才们写的一些只能计算的二进制序列而已。但是随着技术的发展&#xff0c;软件的复杂度不…

CSS---flex布局

主要记录flex布局的要点以及实例 flex flex父标签的6个属性flex-direction: flex布局的方向flex-wrap: 是否可以换行flex-flow: flex-direction 和 flex-wrap 一起写justify-content&#xff1a;横向对齐方式align-items: 纵向对齐方式align-content: 有换行情况下的纵向对齐方…