Java常用锁synchronized和ReentrantLock的区别

目录
  • 区别1:用法不同
    • synchronized 基础使用
    • ReentrantLock 基础使用
  • 区别2:获取锁和释放锁方式不同
  • 区别3:锁类型不同
  • 区别4:响应中断不同
  • 区别5:底层实现不同
  • 小结

前言:

在 Java 中,常用的锁有两种:synchronized(内置锁)和 ReentrantLock(可重入锁),二者的功效都是相同得,但又有很多不同点,所以我们今天就来聊聊。

区别1:用法不同

synchronized 可用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用在代码块上。

synchronized 基础使用

使用 synchronized 修饰代码块:

public void method() {
    // 加锁代码
    synchronized (this) {
        // ...
    }
}

ReentrantLock 基础使用

ReentrantLock 在使用之前需要先创建 ReentrantLock 对象,然后使用 lock 方法进行加锁,使用完之后再调用 unlock 方法释放锁,具体使用如下:

public class LockExample {
    // 创建锁对象
    private final ReentrantLock lock = new ReentrantLock();
    public void method() {
        // 加锁操作
        lock.lock();
        try {
            // ...
        } finally {
            // 释放锁
            lock.unlock();
        }
    }
}

区别2:获取锁和释放锁方式不同

synchronized 会自动加锁和释放锁,当进入 synchronized 修饰的代码块之后会自动加锁,当离开 synchronized 的代码段之后会自动释放锁,

如下图所示: 

而 ReentrantLock 需要手动加锁和释放锁如下图所示: 

PS:在使用 ReentrantLock 时要特别小心,unlock 释放锁的操作一定要放在 finally 中,否者有可能会出现锁一直被占用,从而导致其他线程一直阻塞的问题。

区别3:锁类型不同

synchronized 属于非公平锁,而 ReentrantLock 既可以是公平锁也可以是非公平锁。

默认情况下 ReentrantLock 为非公平锁,这点查看源码可知:

 使用 new ReentrantLock(true) 可以创建公平锁,查看源码可知:

区别4:响应中断不同

ReentrantLock 可以使用 lockInterruptibly 获取锁并响应中断指令,而 synchronized 不能响应中断,也就是如果发生了死锁,使用 synchronized 会一直等待下去,而使用 ReentrantLock 可以响应中断并释放锁,从而解决死锁的问题,比如以下 ReentrantLock 响应中断的示例:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockInterrupt {
    static Lock lockA = new ReentrantLock();
    static Lock lockB = new ReentrantLock();
    public static void main(String[] args) throws InterruptedException {
        // 线程 1:先获取 lockA 再获取 lockB
        Thread t1 = new Thread(() -> {
            try {
                // 先获取 LockA
                lockA.lockInterruptibly();
                // 休眠 10 毫秒
                TimeUnit.MILLISECONDS.sleep(100);
                // 获取 LockB
                lockB.lockInterruptibly();
            } catch (InterruptedException e) {
                System.out.println("响应中断指令");
            } finally {
                // 释放锁
                lockA.unlock();
                lockB.unlock();
                System.out.println("线程 1 执行完成。");
            }
        });
        // 线程 2:先获取 lockB 再获取 lockA
        Thread t2 = new Thread(() -> {
            try {
                // 先获取 LockB
                lockB.lockInterruptibly();
                // 休眠 10 毫秒
                TimeUnit.MILLISECONDS.sleep(100);
                // 获取 LockA
                lockA.lockInterruptibly();
            } catch (InterruptedException e) {
                System.out.println("响应中断指令");
            } finally {
                // 释放锁
                lockB.unlock();
                lockA.unlock();
                System.out.println("线程 2 执行完成。");
            }
        });
        t1.start();
        t2.start();
        TimeUnit.SECONDS.sleep(1);
        // 线程1:执行中断
        t1.interrupt();
    }
}

以上程序的执行结果如下所示: 

区别5:底层实现不同

synchronized 是 JVM 层面通过监视器(Monitor)实现的,而 ReentrantLock 是通过 AQS(AbstractQueuedSynchronizer)程序级别的 API 实现。 synchronized 通过监视器实现,可通过观察编译后的字节码得出结论,

如下图所示: 

其中 monitorenter 表示进入监视器,相当于加锁操作,而 monitorexit 表示退出监视器,相当于释放锁的操作。 ReentrantLock 是通过 AQS 实现,可通过观察 ReentrantLock 的源码得出结论,核心实现源码如下:

小结

synchronized 和 ReentrantLock 都是 Java 中提供的可重入锁,二者的主要区别有以下 5 个:

  • 用法不同:synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块。
  • 获取锁和释放锁的机制不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。
  • 锁类型不同:synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁。
  • 响应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。
  • 底层实现不同:synchronized 是 JVM 层面通过监视器实现的,而 ReentrantLock 是基于 AQS 实现的。

到此这篇关于Java常用锁synchronized和ReentrantLock的区别的文章就介绍到这了,更多相关Java 锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java线程安全解决方案(synchronized,ReentrantLock,Atomic)

    线程安全解决方案 synchronized,ReentrantLock,Atomic 使用场景描述 在实际开发过程中如果服务量,请求频繁,就会经常碰见并发,这时候不做处理就会出现很多非法数据.这时候就需要解决线程安全的问题,这时候就可以使用java当中的锁机制.常用有java关键synchronized.可重入锁ReentrantLock,还有并发包下的Atomic 或者Concurrent的安全类型. synchronized使用场景: 在资源竞争不是很激烈的情况下,偶尔出现并发,需要同步的情

  • 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    synchronized 和 Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢?是仅仅增加了一种选择还是另有其因?本文为您一探究竟. // synchronized关键字用法示例 public synchronized void add(int t){// 同步方法 this.v += t; } public stati

  • Java常用锁synchronized和ReentrantLock的区别

    目录 区别1:用法不同 synchronized 基础使用 ReentrantLock 基础使用 区别2:获取锁和释放锁方式不同 区别3:锁类型不同 区别4:响应中断不同 区别5:底层实现不同 小结 前言: 在 Java 中,常用的锁有两种:synchronized(内置锁)和 ReentrantLock(可重入锁),二者的功效都是相同得,但又有很多不同点,所以我们今天就来聊聊. 区别1:用法不同 synchronized 可用来修饰普通方法.静态方法和代码块,而 ReentrantLock 只

  • Java 同步锁(synchronized)详解及实例

    Java 同步锁(synchronized)详解及实例 Java中cpu分给每个线程的时间片是随机的并且在Java中好多都是多个线程共用一个资源,比如火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源.如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦.比如下面程序: package com.pakage.ThreadAndRunnable; public class Ru

  • Java同步锁Synchronized底层源码和原理剖析(推荐)

    目录 1 synchronized场景回顾 2 反汇编寻找锁实现原理 3 synchronized虚拟机源码 3.1 HotSpot源码Monitor生成 3.2 HotSpot源码之Monitor竞争 3.3 HotSpot源码之Monitor等待 3.4 HotSpot源码之Monitor释放 1 synchronized场景回顾 目标:synchronized回顾(锁分类–>多线程)概念synchronized:是Java中的关键字,是一种同步锁.Java中锁分为以下几种:乐观锁.悲观锁(

  • Java编程synchronized与lock的区别【推荐】

    前言 本文介绍了Java编程synchronized与lock的区别的相关内容,如果您对synchronized与lock不太了解,这两篇文章 或许是不错的选择: Java 同步锁(synchronized)详解及实例 Java多线程基础--Lock类 正文 从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问,那就是Lock. 也许有朋友会问,既然都可以通过synchronized来实现同步访问了,那么为什么还需要提供Lock?这个问题

  • ​​​​​​​Java公平锁和非公平锁的区别

    目录 正文 应用场景 公平和非公平锁代码演示 执行流程分析 公平锁执行流程 非公平锁执行流程 优缺点分析 总结 前言: 从公平的角度来说,Java 中的锁总共可分为两类:公平锁和非公平锁.但公平锁和非公平锁有哪些区别?孰优孰劣呢?在 Java 中的应用场景又有哪些呢?接下来我们一起来看. 正文 公平锁:每个线程获取锁的顺序是按照线程访问锁的先后顺序获取的,最前面的线程总是最先获取到锁.非公平锁:每个线程获取锁的顺序是随机的,并不会遵循先来先得的规则,所有线程会竞争获取锁.  举个例子:公平锁就像

  • Java 多线程Synchronized和Lock的区别

    引言 在多线程中,为了使线程安全,我们经常会使用synchronized和Lock进行代码同步和加锁,但是具体两者有什么区别,什么场景下适合用什么可能还不大清楚,主要的区别大致如下: 区别 1.synchronized是java关键字,而Lock是java中的一个接口 2.synchronized会自动释放锁,而Lock必须手动释放锁 3.synchronized是不可中断的,Lock可以中断也可以不中断 4.通过Lock可以知道线程有没有拿到锁,而synchronized不能 5.synchr

  • 关于synchronized、volatile、ReentrantLock的区别与对比

    目录 并发编程特性 volatile 特性: 作用的地方: synchronized 特性 作用的地方 修饰方法,分为实例方法和静态方法 修饰代码块 ReentrantLock 特性 作用的地方 做为成员变量使用格式: 做为局部变量使用格式: 对比 聊之前先说一下并发编程的3个特性. 并发编程特性 原子性:对共享资源的一组操作,要么成功要么失败,不会出现部分成功部分失败的情况. 可见性: 当线程获取到琐时,会拷贝一份共享资源到本地内存,释放锁时会将共享资源刷新到主内存中.可见性是指当共享资源发生

  • Java线程安全和锁Synchronized知识点详解

    一.进程与线程的概念 (1)在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单位都是进程. 在未配置 OS 的系统中,程序的执行方式是顺序执行,即必须在一个程序执行完后,才允许另一个程序执行:在多道程序环境下,则允许多个程序并发执行.程序的这两种执行方式间有着显著的不同.也正是程序并发执行时的这种特征,才导致了在操作系统中引入进程的概念. 自从在 20 世纪 60 年代人们提出了进程的概念后,在 OS 中一直都是以进程作为能拥有资源和独立运行的基本单位的.直到 20 世纪 8

  • java Volatile与Synchronized的区别

    引言 在研究并发程序时,我们可能都知道volatile和synchronized是用于多线程中,用于线程安全和变量可见性的,但是具体两者怎么使用,有何区别可能还是稀里糊涂一知半解,在此就自己简单的理解总结一下二者的区别,和大家一块儿学习!我们需要了解java中关键字volatile和synchronized关键字的使用以及lock类的用法. 首先,了解下java的内存模型: java的线程内存模型中定义了每个线程都有一份自己的共享变量副本(本地内存),里面存放自己私有的数据,其他线程不能直接访问

随机推荐