Synchronized和Lock、AQS

Synchronized和lock的区别

  1. 本质和类型
  • Synchronized:是Java中的一个关键字,它属于JVM层面,由内置语言实现。
  • Lock:是Java中的一个接口(java.util.concurrent.locks.Lock),需要通过实现它的类(如ReentrantLock)来使用,属于JDK层面,通过代码实现。
  1. 锁的获取和释放
  • Synchronized:隐式地获取和释放锁。当线程进入synchronized代码块或方法时,会自动获取锁;当线程执行完毕或抛出异常时,会自动释放锁。
  • Lock:显式地获取和释放锁。需要通过调用lock()方法来获取锁,并在finally块中调用unlock()方法来释放锁,以确保锁的正确释放。
  1. 锁的灵活性
  • Synchronized:提供的锁是非中断的、不可判断的(无法判断锁是否被持有)、非公平的(线程获取锁的顺序是不确定的)。
  • Lock:提供了更高的灵活性。Lock是可中断的(可以通过lockInterruptibly()方法中断等待锁的线程)、可判断的(可以通过tryLock()等方法判断锁是否可用)、公平的(可以通过构造ReentrantLock时传入true参数来创建公平锁,确保等待时间最长的线程先获取锁)。
  1. 锁的性能
  • Synchronized:在JVM层面实现,优化较好,但在大量同步代码块时可能会有性能问题。
  • Lock:由于可以手动控制锁的获取和释放,以及支持多种锁的特性(如可中断、可判断、公平锁等),因此在某些情况下可以提供更好的性能。但这也需要程序员更加小心地管理锁,以避免死锁等问题。
  1. 使用场景
  • Synchronized:适用于简单的同步场景,如少量的同步代码块或方法。
  • Lock:适用于需要更灵活控制锁的场景,如需要手动中断等待锁的线程、需要判断锁是否可用、需要实现公平锁等。
  1. 底层实现
  • Synchronized:基于JVM的内置锁机制,具体实现依赖于JVM的实现。
    Lock:基于AQS(AbstractQueuedSynchronizer)框架实现,这是一个用于构建锁和其他同步类的框架。
    综上所述,Synchronized和Lock各有优缺点,选择哪个取决于具体的应用场景和需求。在大多数情况下,Synchronized已经足够满足需求,因为它简单且易于使用。但在需要更精细控制锁的场景下,Lock可能是一个更好的选择。

Synchronized

Synchronized详解

  • Synchronized是Java中的一个关键字,用于控制多线程的访问,确保同一时刻只有一个线程可以进入临界区(即被synchronized保护的代码块或方法)。它主要用于保护多线程环境下对共享资源访问的安全性

底层原理

  • Synchronized的底层实现主要依赖于JVM中的monitor对象(也称为管程或监视器)。每个Java对象都有一个与之关联的monitor对象,该对象由JVM的C++代码实现,具体表现为ObjectMonitor。当一个线程进入synchronized代码块或方法时,它会尝试获取与对象关联的monitor对象的锁。如果获取成功,则线程进入临界区执行代码;如果获取失败(即锁已被其他线程持有),则线程会被阻塞,直到锁被释放。
  • monitor对象内部包含了一些关键的字段,如:
    • _owner:指向当前持有锁的线程。
    • _EntryList:关联没有抢到锁的线程,这些线程处于阻塞状态。
    • _WaitSet:关联调用了wait方法的线程,这些线程处于等待状态。
      synchronized的锁释放是自动的,当线程退出synchronized代码块或方法时,JVM会自动释放锁。

锁升级过程和原理
在Java中,锁的升级过程主要是为了优化性能,减少不必要的锁竞争和上下文切换。synchronized的锁升级过程主要包括以下几个阶段:

  • 无锁状态
    在没有线程竞争的情况下,对象处于无锁状态,线程可以自由访问共享资源。
  • 偏向锁状态
    当一个线程访问同步代码块并获取锁时,JVM会在对象头和栈帧中的锁记录里存储锁偏向的线程ID。以后该线程再次进入同步代码块时,只需比较当前线程ID和对象头中的线程ID是否一致,如果一致则无需进行CAS操作即可直接获取锁。偏向锁的主要目的是减少在单线程环境下的锁竞争和CAS操作。
  • 轻量级锁状态
    当有其他线程来竞争锁时,偏向锁会升级为轻量级锁。轻量级锁通过CAS操作来尝试获取锁,如果成功则线程获得锁;如果失败,则根据具体情况进行锁膨胀或重入处理。轻量级锁的主要目的是减少多线程环境下的锁竞争和上下文切换。
  • 重量级锁状态
    当轻量级锁无法满足需求时(如多个线程频繁竞争锁),锁会进一步升级为重量级锁。重量级锁使用操作系统的互斥量来实现,当线程请求锁时,如果锁被其他线程占用,则线程会被挂起并等待被唤醒。重量级锁的主要目的是保证数据的正确性和一致性,但性能较低。
    锁升级的过程是JVM自动进行的,无需程序员手动干预。通过锁升级机制,JVM可以根据实际情况选择最合适的锁策略,以优化程序的性能。

综上所述,Synchronized是Java中用于控制多线程访问共享资源的关键字,其底层实现依赖于JVM中的monitor对象。通过锁升级机制,JVM可以根据实际情况自动选择合适的锁策略以优化性能。

提示:这里可以添加技术名词解释

例如:

  • Bert
  • GPT 初代
  • GPT-2
  • GPT-3
  • ChatGPT

Lock

Lock是Java并发编程中的一个重要接口,位于java.util.concurrent.locks包下。它提供了比synchronized关键字更广泛的锁操作,能以更优雅的方式处理线程同步问题。Lock接口支持多种锁规则,如重入、公平性等,可以在非阻塞式结构的上下文中使用。Lock接口的实现类主要有ReentrantLock(可重入锁)等。

ReentrantLock 介绍

ReentrantLock是Lock接口的一个实现类,是一个独占式可重入锁。相比synchronized,ReentrantLock提供了更高的灵活性和控制能力,如支持公平锁、非公平锁、可中断、超时等特性。ReentrantLock的底层实现依赖于AbstractQueuedSynchronizer(AQS)同步器。

原理:

  • ReentrantLock的实现原理主要涉及到AQS(AbstractQueuedSynchronizer)同步器和Condition条件队列。AQS是一个用于构建锁和其他同步类的框架,它内部维护了一个状态变量和一个等待队列。对于ReentrantLock来说,状态变量表示当前锁被持有的次数,等待队列用于存放等待获取锁的线程。

  • ReentrantLock通过AQS提供的队列和状态管理机制,实现了可重入锁的机制。当一个线程尝试获取锁时,如果锁的状态为0(表示锁未被持有),则线程可以直接获取锁,并将状态设置为1。如果锁的状态不为0(表示锁已被其他线程持有),则线程将被加入等待队列,并被挂起,直到锁被释放。当持有锁的线程再次尝试获取锁时,如果当前线程已经持有锁,则直接增加状态值;如果不是,则将该线程加入等待队列。当一个线程释放锁时,AQS会将状态值减1,如果状态值为0,则唤醒等待队列中的下一个线程。

公平锁与非公平锁实现原理
ReentrantLock支持公平锁和非公平锁两种模式。

  • 非公平锁(NonfairSync):在尝试获取锁时,不考虑其他线程是否在等待队列中等待锁,直接尝试获取。如果获取成功,则当前线程持有锁;如果失败,则根据AQS的等待队列机制进行等待。非公平锁的优点在于吞吐量比公平锁大,但可能会造成线程饥饿现象.
  • 公平锁(FairSync):在尝试获取锁时,会先检查等待队列是否为空。如果为空或者当前线程是等待队列的第一个,则尝试获取锁;否则,将当前线程加入等待队列,并按照FIFO(先进先出)的规则等待获取锁。公平锁确保了线程按照申请锁的顺序来获取锁,避免了线程饥饿现象,但可能会降低吞吐量。

AQS 的使用原理

AQS(AbstractQueuedSynchronizer)是Java并发包中的一个抽象基类,为实现锁和其他同步器提供了一种统一的框架。AQS内部维护了一个状态变量和一个等待队列。状态变量用于表示被保护资源的状态,等待队列用于存放等待获取资源的线程。

AQS的主要方法包括:

  • acquire(int arg):尝试获取锁。如果获取成功,则返回;如果失败,则将当前线程加入等待队列并阻塞。
  • release(int arg):释放锁。将状态变量减1,如果状态变量变为0,则唤醒等待队列中的下一个线程。
  • tryAcquire(int acquires):尝试获取锁,但不阻塞当前线程。如果获取成功,则返回true;如果失败,则返回false。
  • tryRelease(int releases):尝试释放锁,但不唤醒等待线程。如果释放成功,则返回true;如果失败,则返回false。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值