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();
        }
    }
相关文章
|
4月前
synchronized与ReentrantLock区别与联系
synchronized与ReentrantLock区别与联系
22 0
|
9月前
|
算法 调度
JUC基础(三)—— Lock锁 及 AQS(1)
JUC基础(三)—— Lock锁 及 AQS
83 0
|
9月前
|
Java
JUC基础(三)—— Lock锁 及 AQS(2)
JUC基础(三)—— Lock锁 及 AQS
65 0
|
10月前
|
存储 Java
09.什么是synchronized的重量级锁?
大家好,我是王有志。今天我们学习synchronized升级过程中的最后一部分,从轻量级锁升级到重量级锁的过程。
119 0
09.什么是synchronized的重量级锁?
线程同步的方法:Synchronized、Lock、ReentrantLock分析
线程同步的方法:Synchronized、Lock、ReentrantLock分析
|
安全 Java 对象存储
浅谈synchronized锁原理
保证线程安全的一个重要手段就是通过加锁的形式实现,今天盘点一下Java中锁的八股文
129 0
|
安全 Java
多线程详解p18、Lock锁
多线程详解p18、Lock锁
synchronized与ReentrantLock有什么区别
synchronized与ReentrantLock区别之处
85 0
|
安全 Java
synchronized 和 ReentrantLock 有什么区别?
synchronized 和 ReentrantLock 有什么区别?
149 0
synchronized 和 ReentrantLock 有什么区别?
|
安全 Java 调度
多线程同步问题,锁Lock,synchronized
线程同步机制 并发:同一个对象被多个线程同时操作 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步。线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个县城再使用 线程同步形成条件:队列+