✨Java并发编程:Synchronized与ReentrantLock的比较

5 篇文章 0 订阅
1 篇文章 0 订阅

✨探索Java并发编程:Synchronized与ReentrantLock的比较✨

在Java多线程编程中,确保线程安全是至关重要的。为此,Java提供了多种机制来实现同步操作。其中,synchronized关键字和java.util.concurrent.locks.ReentrantLock类是最常用的两种方式。本文将探讨这两种机制之间的主要区别,以帮助开发者更好地选择适合其应用场景的技术。

Synchronized 关键字

synchronized关键字是Java语言内置的一种互斥锁机制,它能够保证在同一时刻只有一个线程可以执行特定的代码段(临界区)。它可以应用于方法级别或代码块级别。

特点:

  • 简洁性:使用简单,直接修饰方法或声明同步代码块。
  • 不可中断:一旦一个线程获取了锁,其他等待该锁的线程必须等到锁被释放,无法强制中断。
  • 自动释放:当发生异常时,JVM会自动释放锁。
  • 非公平锁:默认情况下,synchronized采用的是非公平策略,即先抢到锁的线程可以优先执行。
  • 性能:随着JDK版本更新,如自适应自旋、锁消除等优化技术的应用,synchronized的性能得到了显著提升。

使用Synchronized关键字实现同步

public class SynchronizedExample {
    // 定义私有变量 count 表示计数
    private int count = 0;

    // 使用 synchronized 关键字修饰的方法,实现对 count 的递增操作
    public synchronized void increment() {
        count++;
    }

    // 使用 synchronized 关键字修饰的方法,获取当前 count 的值
    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();
        Runnable runnable = () -> {
            for (int i = 0; i < 1000; i++) {
                // 每个线程执行 1000 次递增操作
                example.increment();
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();
        try {
            // 等待 thread1 执行完毕
            thread1.join();
            // 等待 thread2 执行完毕
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 输出最终的计数结果
        System.out.println("Synchronized count: " + example.getCount());
    }
}

ReentrantLock 类

ReentrantLock是Java 5之后引入的一个显式锁接口Lock的具体实现,它提供了比 synchronized 更加丰富的功能。

特点:

  • 灵活性:支持尝试获取锁、定时等待等功能。
  • 可中断:允许线程在等待锁的过程中响应中断请求。
  • 手动管理:需要程序员手动获取和释放锁,这增加了出错的可能性。
  • 公平/非公平选择:可以通过构造函数参数设置为公平锁或非公平锁。
  • 条件变量:提供Condition对象,可用于更复杂的线程间通信场景。

使用ReentrantLock实现同步

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    // 定义私有变量 count 表示计数
    private int count = 0;
    // 创建 ReentrantLock 对象用于实现同步
    private ReentrantLock lock = new ReentrantLock();

    // 实现对 count 的递增操作,使用 ReentrantLock 进行同步
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            // 确保在任何情况下都能释放锁
            lock.unlock();
        }
    }

    // 获取当前 count 的值
    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();
        Runnable runnable = () -> {
            for (int i = 0; i < 1000; i++) {
                // 每个线程执行 1000 次递增操作
                example.increment();
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();
        try {
            // 等待 thread1 执行完毕
            thread1.join();
            // 等待 thread2 执行完毕
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 输出最终的计数结果
        System.out.println("ReentrantLock count: " + example.getCount());
    }
}

比较总结

特性SynchronizedReentrantLock
使用方便
锁的细粒度控制有限
可中断
公平锁选项
性能现代JVM下接近甚至优于ReentrantLock取决于具体用例

结论

虽然ReentrantLock提供了更多高级特性,但在大多数基本场景下,synchronized已经足够强大且易于使用。只有当你确实需要利用ReentrantLock提供的额外功能时(例如条件变量、可中断锁等),才应考虑使用它。

觉得有用的话可以点点赞 (*/ω\*),支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值