美文网首页
锁 | 内置锁和手动锁的区别

锁 | 内置锁和手动锁的区别

作者: 七喜丶 | 来源:发表于2022-05-16 14:12 被阅读0次

在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修饰的代码块之后会自动加锁,当离开synchronize的代码段之后会自动释放锁。而ReentrantLock需要手动加锁和释放锁

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

3. 锁类型不同

synchronized属于非公平锁,而ReentrantLock既可以是公平锁也可以实非公平锁。默认情况下ReentrantLock为非公平锁,源码可知:

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

4.响应中断不同

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

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 的源码得出结论,核心实现源码如下:

相关文章

  • 锁 | 内置锁和手动锁的区别

    在Java中,常见的锁有二种:synchronized(内置锁)和ReentrantLock(手动锁,及可重入锁)...

  • Java 显示锁和AQS 一

    内置锁和显示锁 显示锁接口: Lock(); 内置锁: Synchronize(); 显示锁的不同 lockInt...

  • 05.锁机制和条件对象简述

    Java的锁机制主要分内置锁(隐式锁)和显式锁。 内置锁 Java每个对象都有一个内置的锁对象,这些锁对象不需要显...

  • Java对象锁和类锁

    java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的...

  • 线程安全,内存可见性,竞态条件,内置锁,显式锁概述

    线程安全,内存可见性,竞态条件,内置锁,显式锁概述 在Java中按照锁的实现方式可以划分为内置锁和显式锁,内置锁有...

  • java-summery

    1、对象锁和类锁 java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码...

  • 对synchronized的一点理解

    定义 Java中具有通过synchronized实现的内置锁,内置锁获取锁和释放锁的过程是隐式的,进入synchr...

  • 【锁】

    1、锁类型 jdk1.5之前1、内置锁2、volatile jdk1.51、ReentrantLock 2、区别 ...

  • 加锁机制--线程安全性

    加锁机制:内置锁和重入 内置锁: java提供了一种内置的锁机制来支持原子性:同步代码块(Synchronized...

  • JUC(一) | 同步辅助类浅谈

    Java多线程环境中存在内置锁与同步锁,内置锁即由synchronized修饰的代码,借助于对象的内置锁实现,为重...

网友评论

      本文标题:锁 | 内置锁和手动锁的区别

      本文链接:https://www.haomeiwen.com/subject/yazcurtx.html