synchronized和ReentrantLock区别和联系

2024-03-20 1485阅读

温馨提示:这篇文章已超过430天没有更新,请注意相关的内容是否还可用!

synchronized 和 ReentrantLock 都是 Java 中用于实现线程同步的机制,它们都可以用于控制多个线程对共享资源的访问。以下是它们的一些比较:

synchronized和ReentrantLock区别和联系
(图片来源网络,侵删)
  1. 锁的获取方式:

    • synchronized:通过关键字 synchronized 可以直接对代码块或方法进行加锁,Java 虚拟机会自动管理锁的获取和释放。
    • ReentrantLock:通过 ReentrantLock 类的实例来获取锁,并通过 lock() 方法来加锁,unlock() 方法来释放锁。需要手动管理锁的获取和释放。
    • 可重入性:

      可重入性指的是同一个线程在持有锁的情况下,可以再次获取这个锁,而不会被自己持有的锁所阻塞。这个特性在并发编程中是非常重要的,因为它允许线程在调用一个已经拥有锁的同步方法时,不会因为锁的重入而发生死锁。

让我们通过一个示例来说明可重入性:

public class ReentrantExample {
    private final Object lock = new Object();
    public void outer() {
        synchronized (lock) {
            System.out.println("Outer method");
            inner();
        }
    }
    public void inner() {
        synchronized (lock) {
            System.out.println("Inner method");
        }
    }
    public static void main(String[] args) {
        ReentrantExample example = new ReentrantExample();
        example.outer();
    }
}

在这个示例中,outer() 方法和 inner() 方法都使用了同一个锁对象 lock 进行同步。当线程调用 outer() 方法时,它会获取 lock 上的锁,并执行 inner() 方法。在 inner() 方法中,由于它也在同一个锁上进行同步,所以即使是在 outer() 方法已经持有锁的情况下,也能够再次获得这个锁,而不会被阻塞。

同样的原理也适用于 ReentrantLock。当一个线程持有 ReentrantLock 锁时,它可以多次调用 lock() 方法来再次获取这个锁,而不会被自己持有的锁所阻塞。这种可重入性确保了线程在执行同步代码块时不会因为持有锁而发生死锁。

  1. 灵活性:
    • synchronized:synchronized 关键字的使用比较简单,可以直接修饰方法或代码块,不需要显示地创建锁对象。但是它的灵活性相对较差,例如不能设置超时时间、不能中断正在等待的线程等。
    • ReentrantLock:ReentrantLock 提供了比较丰富的功能,例如可以设置公平/非公平锁、可中断的获取锁、定时的获取锁等。

      确实,ReentrantLock 提供了一些高级功能,包括:

公平/非公平锁: 可以通过构造函数来指定 ReentrantLock 是公平锁还是非公平锁。公平锁会按照线程的请求顺序来获取锁,而非公平锁则允许线程插队获取锁。默认情况下,ReentrantLock 是非公平的。

可中断的获取锁: ReentrantLock 提供了 lockInterruptibly() 方法,允许线程在等待锁的过程中被中断。如果一个线程在等待锁时被中断,它会收到 InterruptedException 异常。

定时的获取锁: ReentrantLock 提供了 tryLock(long time, TimeUnit unit) 方法,允许线程在指定的时间范围内尝试获取锁。如果在指定的时间内没有获取到锁,该方法会返回 false。

下面是一个示例,演示了如何使用 ReentrantLock 的这些高级功能:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockAdvancedExample {
    public static void main(String[] args) throws InterruptedException {
        Lock fairLock = new ReentrantLock(true); // 创建公平锁
        Lock nonFairLock = new ReentrantLock();   // 创建非公平锁
        // 公平锁示例
        Thread fairThread1 = new Thread(() -> {
            fairLock.lock();
            try {
                System.out.println("Fair lock acquired by Thread 1");
                Thread.sleep(1000); // 模拟占用锁的一段时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                fairLock.unlock();
            }
        });
        Thread fairThread2 = new Thread(() -> {
            fairLock.lock();
            try {
                System.out.println("Fair lock acquired by Thread 2");
            } finally {
                fairLock.unlock();
            }
        });
        // 非公平锁示例
        Thread nonFairThread1 = new Thread(() -> {
            nonFairLock.lock();
            try {
                System.out.println("Non-fair lock acquired by Thread 1");
                Thread.sleep(1000); // 模拟占用锁的一段时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                nonFairLock.unlock();
            }
        });
        Thread nonFairThread2 = new Thread(() -> {
            nonFairLock.lock();
            try {
                System.out.println("Non-fair lock acquired by Thread 2");
            } finally {
                nonFairLock.unlock();
            }
        });
        // 启动线程
        fairThread1.start();
        fairThread2.start();
        nonFairThread1.start();
        nonFairThread2.start();
        // 等待线程执行完毕
        fairThread1.join();
        fairThread2.join();
        nonFairThread1.join();
        nonFairThread2.join();
        System.out.println("All threads completed.");
    }
}

在这个示例中,我们创建了两个 ReentrantLock 实例,一个是公平锁,另一个是非公平锁。然后创建了两个线程分别尝试获取这两种锁,演示了公平锁和非公平锁的区别。

  1. 性能:

    • 通常情况下,synchronized 的性能会比 ReentrantLock 好,因为它是由 JVM 内部实现的,具有较低的开销。
    • 但在一些特殊情况下,ReentrantLock 的性能可能会优于 synchronized,例如需要支持公平锁、需要手动管理锁的释放等情况。
    • 可读性:

      • synchronized 相对于 ReentrantLock 来说,使用更简单、更直观,对于一些简单的场景,代码可读性更好。
      • ReentrantLock 由于需要手动管理锁的获取和释放,可能会使得代码相对复杂一些,但也提供了更多的灵活性和控制能力。

        好的,让我们通过几个示例来说明 synchronized 和 ReentrantLock 的用法和区别。

示例1: 使用 synchronized 进行线程同步

public class SynchronizedExample {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public synchronized int getCount() {
        return count;
    }
    public static void main(String[] args) throws InterruptedException {
        SynchronizedExample example = new SynchronizedExample();
        Runnable task = () -> {
            for (int i = 0; i  

在上面的示例中,increment() 方法和 getCount() 方法都被 synchronized 修饰,这意味着在同一时间只有一个线程可以执行这两个方法中的任意一个。这样就保证了 count 的线程安全性。

示例2: 使用 ReentrantLock 进行线程同步

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockExample example = new ReentrantLockExample();
        Runnable task = () -> {
            for (int i = 0; i  

在这个示例中,我们使用了 ReentrantLock 来实现线程同步。通过调用 lock() 和 unlock() 方法来手动管理锁的获取和释放。这样就保证了在同一时间只有一个线程可以执行 increment() 和 getCount() 方法中的任意一个。

综上所述,对于大多数情况下的简单线程同步需求,可以使用 synchronized。而对于一些特殊的需求,例如需要更多的灵活性、更精细的控制、更好的性能等,可以选择使用 ReentrantLock。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]