JUC 源码解析:lock锁与synchronized锁的区别

JUC 源码解析:lock锁与synchronized锁的区别

本文使用 jdk1.8

Lock 锁的使用注意事项

  • 要在 finally 块中释放锁。保障锁一定能被释放
  • 不要把加锁代码写进 try 块里。因为我们可能会自己实现Lock接口,在一些实现中,如果获取锁时发生了异常,可能导致锁被无故释放

lock 与 synchronized 的区别

1. synchronized 拓展性和灵活性不如 Lock

  • synchronized 能隐式的获取锁释放锁,虽然方便,但lock纯手动显得更灵活。

  • Lock 接口可以自己写实现类,可以实现很多自定义的方法,synchronized与它相比非常呆板


2. jstack 线程状态不同

使用 lock 加锁,和使用 synchronized 加锁。没拿到锁的线程,状态是不同的。

  • 线程如果没有竞争到 synchronized 锁,会呈现出 blocked 阻塞状态

  • 线程如果没有竞争到 Lock 锁,会呈现出 waiting 等待状态

来用代码演示看看,先看看synchronized锁状态:

static SheepLock lock = new SheepLock();

public static void main(String[] args) throws InterruptedException {
    new Thread(Main::trySheepLock, "A").start();
    new Thread(Main::trySheepLock, "B").start();


}

public static void trySheepLock() {
    synchronized (lock) {
        System.out.println(Thread.currentThread().getName() + "获取到小羊锁");

        while (true) {} // 无限循环,不释放锁
    }
}

在终端中用这样的命令查看 jstack 日志:

在日志中找到这A、B这两个线程

可以看到:

  • A抢到了锁,线程状态是 RUNNABLE
  • B没有抢到锁,线程状态是 BLOCKED ,是阻塞

把这段代码改成 Lock 锁,然后用相同的方法看看锁状态(SheepLock 是我自定义的Lock实现,可以满足基本的锁需求)

static SheepLock lock = new SheepLock();

public static void main(String[] args) throws InterruptedException {
    new Thread(Main::trySheepLock, "A").start();
    new Thread(Main::trySheepLock, "B").start();
}

public static void trySheepLock() {

    lock.lock();
    try {
        System.out.println(Thread.currentThread().getName() + "获取到小羊锁");
        while (true) {} // 无限循环,不释放锁

    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        lock.unlock();
    }

}

可以看到:

  • 线程A抢到了锁,状态是 RUNNABLE
  • 线程B没有抢到锁,状态是WATTING,是等待

3. Lock 可以响应中断

Lock 接口中有这样的方法定义

void lockInterruptibly() throws InterruptedException;

与 synchronized 不同,Lock 的这个方法可以响应中断。

当拿到锁的线程被中断时,异常会抛出,锁会被释放


4. Lock 可以设置:在截止时间之前获取锁

Lock 接口中有这样的方法定义:

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

Lock 可以设置在截止时间之前获取锁,如果获取不到,会返回 false


5. Lock 可尝试非阻塞(非等待)获得锁

Lock 接口中有这样的方法定义:

boolean tryLock();

它可以尝试获取锁,只尝试一次,而不会让线程CAS自旋,失败一次就返回 false

posted @ 2024-05-14 17:11  yangruomao  阅读(8)  评论(0编辑  收藏  举报