synchronized和锁(ReentrantLock) 区别

本文详细比较了Java中的synchronized与ReentrantLock两种同步机制的区别,包括使用方式、等待可中断特性、公平锁机制、锁绑定多个条件以及性能方面的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5ibc.net纯属抄袭本文

转载请注明出处
作者:小风筝0010
原文:http://blog.youkuaiyun.com/zheng548/article/details/54426947

区别一:API层面

synchronized使用

synchronized既可以修饰方法,也可以修饰代码块。
synchronized修饰方法时,如下所示:

//synchronized修饰一个方法时,这个方法叫同步方法。
public synchronized void test() {
//方法体``

}

synchroized修饰代码块时,包含两部分:锁对象的引用和这个锁保护的代码块。如下所示:

synchronized(Object) {
//括号中表示需要锁的对象.
//线程执行的时候会对Object上锁
}

ReentrantLock使用

public class test(){
    private Lock lock = new ReentrantLock();

    public void testMethod()
    {
        try
        {
            lock.lock();
            ```
            //省略

        }
        finally
        {
            lock.unlock();
        }
    }
}

区别二:等待可中断

引用周志明的《深入理解Java虚拟机》Page 392

等待可中断是指当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。可等待特性对处理执行时间非常长的同步快很有帮助。

具体来说,假如业务代码中有两个线程,Thread1 Thread2。假设 Thread1 获取了对象object的锁,Thread2将等待Thread1释放object的锁。

  • 使用synchronized。如果Thread1不释放,Thread2将一直等待,不能被中断。synchronized也可以说是Java提供的原子性内置锁机制。内部锁扮演了互斥锁(mutual exclusion lock ,mutex)的角色,一个线程引用锁的时候,别的线程阻塞等待。

  • 使用ReentrantLock。如果Thread1不释放,Thread2等待了很长时间以后,可以中断等待,转而去做别的事情。

区别三:公平锁

引用周志明的《深入理解Java虚拟机》Page 392

公平锁是指多个线程在等待同一个锁时,必须按照申请的时间顺序来依次获得锁;而非公平锁则不能保证这一点。非公平锁在锁被释放时,任何一个等待锁的线程都有机会获得锁。
synchronized的锁是非公平锁,ReentrantLock默认情况下也是非公平锁,但可以通过带布尔值的构造函数要求使用公平锁。

区别四:锁绑定多个条件

ReentrantLock可以同时绑定多个Condition对象,只需多次调用newCondition方法即可。
synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含的条件。但如果要和多于一个的条件关联的时候,就不得不额外添加一个锁。

区别五:性能

JDK 1.5中,synchronized还有很大的优化余地。JDK 1.6 中加入了很多针对锁的优化措施,synchronized与ReentrantLock性能方面基本持平。虚拟机在未来的改进中更偏向于原生的synchronized。

补充:关于synchronized关键字

  1. Java中每个对象都有一个锁(lock)或者叫做监视器(monitor)。
  2. ReentrantLock和synchronized持有的对象监视器不同。
  3. 如果某个synchronized方法是static的,那么当线程方法改方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在对象所对应的Class对象,因为Java中不管一个类有多少对象,这些对象会对应唯一一个Class对象。因此当线程分别访问同一个类的两个对象的两个static,synchronized方法时,是顺序执行的,亦即一个线程先执行,完毕之后,另一个才开始执行。
  4. synchronized 方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行synchronized方法;synchronized块则是一种细粒度的并发控制。只会将块中代码同步,位于方法内,synchronized块之外的代码是可以被多个线程同时访问的。
  5. synchronized关键字经过编译之后,会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令,操作对象均为锁的计数器。
    6.相同点:都是可重入的。可重入值的是同一个线程多次试图获取它所占的锁,请求会成功。当释放的时候,直到冲入次数清零,锁才释放。
Java中,`synchronized``ReentrantLock`是两种用于实现线程同步的机制,它们在功能上有一些相似之处,但在灵活性、功能丰富性使用方式上存在显著差异。 ### 使用方式 `synchronized`是Java语言的关键字,它属于原生语法层面的互斥机制,由JVM直接支持管理。使用`synchronized`时,开发者不需要显式地获取释放的获取释放是由JVM自动完成的。例如,当一个线程进入由`synchronized`修饰的方法或代码块时,它会自动获取;当离开该方法或代码块时,会被自动释放[^3]。 相比之下,`ReentrantLock`是JDK 1.5之后提供的API层面的互斥,它是通过Java代码实现的一个类。使用`ReentrantLock`时,开发者需要显式地调用`lock()`方法来获取,并且在finally块中调用`unlock()`方法来释放,以确保即使在发生异常的情况下也能正确释放[^3]。 ### 功能丰富性 `ReentrantLock`相比`synchronized`提供了更多的功能。例如,`ReentrantLock`支持尝试非阻塞地获取(`tryLock()`)、在获取的过程中可以响应中断(`lockInterruptibly()`)以及设置超时时间(`tryLock(long time, TimeUnit unit)`)。这些功能使得`ReentrantLock`在处理复杂的并发场景时更加灵活强大[^1]。 ### 性能表现 在早期版本的Java中,`ReentrantLock`通常比`synchronized`具有更好的性能表现,尤其是在高竞争环境下。然而,从Java 6开始,随着JVM对`synchronized`进行了大量优化,包括引入了偏向、轻量级等机制,`synchronized`的性能已经得到了显著提升,使得两者之间的性能差距大大缩小[^1]。 ### 错误处理与调试 尽管`ReentrantLock`提供了比`synchronized`更高级的功能,但它也有一些缺点。其中之一是在使用`ReentrantLock`时,如果没有正确地释放,那么很难追踪到最初发生错误的位置,因为没有记录应该释放的位置时间。这可能会导致死或其他难以调试的并发问题[^2]。 ### 示例代码 以下是一个使用`synchronized`的例子: ```java public class SynchronizedExample { public synchronized void method() { // 同步代码 } } ``` 而下面是一个使用`ReentrantLock`的例子: ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample { private final ReentrantLock lock = new ReentrantLock(); public void method() { lock.lock(); try { // 同步代码 } finally { lock.unlock(); } } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值