synchronized 锁与 ReentrantLock 锁的区别

简介: synchronized 锁与 ReentrantLock 锁的区别

相关知识点参考:ConcurrentHashMap 可以使用 ReentrantLock 作为锁吗?

线程可以通过加 synchronized 锁或 ReentrantLock 锁两种方式对代码加锁,实现线程安全。他们的区别如下:

共同点:

(1)都保证了可见性和互斥性

(2)都是可重入锁,同一线程可以多次获得同一个锁

(3)都是用来协调多线程对共享对象、变量的访问

不同点:

(1)synchronized 是 Java 关键字,ReentrantLock 是 lock 的实现类。

(2)synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码

(3)synchronized 在程序发生异常或执行完时会自动释放锁,ReentrantLock 必须要手动释放锁(用 unlock 方法),如果不释放就成了死锁,因此使用 lock 时需要在 finally 块中释放锁。

(4)底层实现不一样,synchronized 是同步阻塞,使用悲观并发策略;ReentrantLock 是同步非阻塞,采用乐观并发策略,所以可以提高多个线程进行读操作的效率。

(5)synchronized 可以把任意一个非 NULL 的对象当做锁,它属于独占式的悲观锁、非公平锁,同时也属于可重入锁。ReentrantLock 继承接口 Lock 并实现了接口中定义的方法,它也是一种可重入锁,同时可以将其设置为公平锁。

(6)synchronized 无法判断获取锁的状态,ReentrantLock 可以判断线程是否获取到了锁,并且可以对获取锁的等待时间进行设置,避免死锁,同时可以获取各种锁的信息以及可以灵活地实现多路通知。

 

ReentrantLock 公平性的设置:

ReentrantLock fairLock = new ReentrantLock(true),参数为 true 时,表明设置为公平锁,会倾向于将锁赋予等待时间最久的线程。

公平锁:获取锁的顺序按先后调用 lock()方法的顺序(慎用),也就是排队一样。

非公平锁:抢占的顺序不一定,随机的。

注意:一般没有强需求按顺序执行的情况下,采用非公平锁好,因为 Java 的 JVM 设置很少情况下才会出现一个线程等待很久没有被分配到资源的情况。然后采用了公平锁的话,会造成一定的性能消耗,导致吞吐量下降。

synchronized 加锁实现方式:

关于同步方法的总结:

  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
  2. 非静态的同步方法,其同步监视器是:this(当前类的对象)

静态同步方法:同步监视器是:当前类本身(类.class ( ))

class Ticket{
    private int num=100;//总共100张票
    public synchronized void sell() throws InterruptedException {
        //此时用synchronized修饰方法sell(),其同步监视器是:this(当前类的对象),由于使用的是
        while(num>0){
            System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+(num--));
            //为了创造一些异常,让线程到此处sleep阻塞一下
            TimeUnit.MILLISECONDS.sleep(10);
        }
    }
}
class Ticket{
    private int num=100;//总共100张票
    public void sell() throws InterruptedException {
        synchronized (this){
            //此时使用synchronized修饰代码块
            while (num > 0) {
                System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + (num--));
                //为了创造一些异常,让线程到此处sleep阻塞一下1
                TimeUnit.MILLISECONDS.sleep(10);
            }
        }
    }
}

ReentrantLock 加锁实现方式:

public void buy() {
        lock.lock();
        try {
            while (num==0){
                //此时没有商品,需要等待
                notNull.await();
            }
            //不为0则可以进行操作
            num--;
            System.out.println(Thread.currentThread().getName()+"消费商品,当前剩余商品:"+num);
           notNull.signalAll();//通知其他线程可以生产商品
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
相关文章
|
8天前
|
缓存 Java
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
本文介绍了几种常见的锁机制,包括公平锁与非公平锁、可重入锁与不可重入锁、自旋锁以及读写锁和互斥锁。公平锁按申请顺序分配锁,而非公平锁允许插队。可重入锁允许线程多次获取同一锁,避免死锁。自旋锁通过循环尝试获取锁,减少上下文切换开销。读写锁区分读锁和写锁,提高并发性能。文章还提供了相关代码示例,帮助理解这些锁的实现和使用场景。
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
|
3月前
|
Java
JUC(11)各种锁的理解(公平锁、可重入锁、自旋锁、死锁)
这篇文章介绍了Java并发包中的各种锁机制,包括公平锁与非公平锁、可重入锁、自旋锁以及死锁的概念、实现和示例,以及如何使用jps和jstack工具来检测和诊断死锁问题。
|
4月前
多线程线程安全问题之synchronized和ReentrantLock在锁的释放上有何不同
多线程线程安全问题之synchronized和ReentrantLock在锁的释放上有何不同
|
4月前
|
存储 设计模式 安全
(五)深入剖析并发之AQS独占锁&重入锁(ReetrantLock)及Condition实现原理
在我们前面的文章《[深入理解Java并发编程之无锁CAS机制》中我们曾提到的CAS机制如果说是整个Java并发编程基础的话,那么本章跟大家所讲述的AQS则是整个Java JUC的核心。不过在学习AQS之前需要对于CAS机制有一定的知识储备,因为CAS在ReetrantLock及AQS中的实现随处可见。
|
4月前
|
安全 Java
Java多线程中的锁机制:深入解析synchronized与ReentrantLock
Java多线程中的锁机制:深入解析synchronized与ReentrantLock
87 0
|
存储 Java
09.什么是synchronized的重量级锁?
大家好,我是王有志。今天我们学习synchronized升级过程中的最后一部分,从轻量级锁升级到重量级锁的过程。
184 0
09.什么是synchronized的重量级锁?
|
安全 Java 对象存储
浅谈synchronized锁原理
保证线程安全的一个重要手段就是通过加锁的形式实现,今天盘点一下Java中锁的八股文
155 0
线程同步的方法:Synchronized、Lock、ReentrantLock分析
线程同步的方法:Synchronized、Lock、ReentrantLock分析
synchronized 锁的是什么?(二)
每个对象都存在着一个 Monitor 对象与之关联。执行 monitorenter 指令就是线程试图去获取 Monitor 的所有权,抢到了就是成功获取锁了;执行 monitorexit 指令则是释放了 Monitor 的所有权。
synchronized 锁的是什么?(二)