深入理解并发编程之 synchronized 和 Lock 的区别

目录

深入理解并发编程之 synchronized 和 Lock 的区别

一、synchronized关键字

二、Lock接口(以ReentrantLock为例)

三、synchronized和Lock的区别

四、前端展示(使用 Vue)


在并发编程领域,理解synchronizedLock(以ReentrantLock为例)的区别对于编写高效、安全的多线程程序至关重要。这篇博客将详细介绍它们之间的差异。

一、synchronized关键字

  1. 基本概念
    synchronized是 Java 中的内置关键字,用于实现方法或代码块的同步。它基于对象的内置锁(monitor)机制。当一个线程访问被synchronized修饰的代码块或方法时,它会自动获取对象的锁,其他试图访问相同对象的同步代码的线程将被阻塞。

  2. 示例代码
    以下是使用synchronized关键字的简单示例:

public class SynchronizedExample {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

在上述代码中,increment方法被synchronized修饰,同一时刻只有一个线程能够执行该方法,保证了对count变量的操作是线程安全的。

二、Lock接口(以ReentrantLock为例)

  1. 基本概念
    Lock是一个接口,ReentrantLock是其一个重要的实现类。它提供了比synchronized更灵活的锁机制。例如,可以手动获取和释放锁、尝试非阻塞地获取锁、可中断地获取锁以及超时获取锁等功能。

  2. 示例代码

import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}

在这个示例中,通过ReentrantLock来实现对count变量的同步操作。在increment方法中,首先使用lock()方法获取锁,然后在finally块中使用unlock()方法释放锁,确保无论是否发生异常,锁都能被正确释放。

三、synchronizedLock的区别

  1. 锁的获取和释放

    • synchronized:由 Java 虚拟机自动获取和释放锁,线程执行完同步代码块或方法后自动释放锁。
    • Lock:需要手动调用lock()方法获取锁,并在finally块中调用unlock()方法释放锁,这给予了程序员更精细的控制,但也增加了出错的可能性(如忘记释放锁)。
  2. 功能特性

    • synchronized:相对简单直接,但功能有限。它是一种隐式的锁机制,不支持尝试获取锁、可中断获取锁等复杂操作。
    • Lock:功能更丰富。例如,可以使用tryLock()方法尝试非阻塞地获取锁,如下代码所示:
if (lock.tryLock()) {
    try {
        // 执行需要同步的代码
    } finally {
        lock.unlock();
    }
} else {
    // 处理获取锁失败的情况
}

还可以使用lockInterruptibly()方法实现可中断地获取锁,这在一些需要响应外部中断信号的场景中非常有用。

  1. 锁的类型和可重入性

    • synchronized:是可重入锁,一个线程可以多次获取同一个对象的锁。例如,一个线程在一个synchronized方法中调用另一个synchronized方法(属于同一个对象),不会产生死锁。
    • LockReentrantLock也是可重入锁,并且可以通过构造函数指定是否为公平锁。公平锁保证了线程获取锁的顺序是按照请求锁的顺序来的,而非公平锁则允许插队获取锁,可能会提高一定的性能,但可能导致某些线程长时间等待。
  2. 性能方面(在某些情况下)

    • 在低竞争场景下,synchronized的性能可能和Lock差不多,因为JVMsynchronized进行了优化。
    • 在高竞争场景下,Lock可能具有更好的性能,特别是当需要使用复杂的锁功能时,如超时获取锁等。

四、前端展示(使用 Vue)

我们可以创建一个简单的 Vue 组件来模拟synchronizedLock的使用情况对比:

<template>
  <div>
    <h2>synchronized 和 Lock 对比演示</h2>
    <button @click="incrementWithSynchronized">使用 synchronized 递增</button>
    <button @click="incrementWithLock">使用 Lock 递增</button>
    <p>synchronized 计数: {
   
   { synchronizedCount }}</p>
    <p>Lock 计数: {
   
   { lockCount }}</p>
  </div>
</template>

<script>
import SynchronizedExample from './SynchronizedExample.js';
import LockExample from './LockExample.js';

export default {
  data() {
    return {
      synchronizedCount: 0,
      lockCount: 0,
      synchronizedObj: new SynchronizedExample(),
      lockObj: new LockExample()
    };
  },
  methods: {
    incrementWithSynchronized() {
      this.synchronizedObj.increment();
      this.synchronizedCount = this.synchronizedObj.getCount();
    },
    incrementWithLock() {
      this.lockObj.increment();
      this.lockCount = this.lockObj.getCount();
    }
  }
};
</script>

<style>
/* 样式代码 */
</style>

通过这个前端界面,我们可以直观地看到在多线程模拟环境下(这里简化为通过按钮点击模拟多线程操作),synchronizedLock对共享变量操作的效果。

总之,synchronizedLock各有优缺点,在实际的并发编程中,需要根据具体的应用场景来选择合适的同步机制,以实现高效、安全的多线程程序。

猜你喜欢

转载自blog.csdn.net/m0_57836225/article/details/143472030