响应式网站需要的技术,做网站对外贸有什么用,免费制作贺卡的app,维护网站英语目录 乐观锁的底层原理
ReentrantLock的实现原理
读写锁 ReentrantReadWriteLock
synchronized 底层原理
Lock和synchronized的区别 乐观锁的底层原理 版本号机制 在数据库表中添加一个版本号字段#xff08;如 version#xff09;#xff0c;每次更新数据时都会将版本号…目录 乐观锁的底层原理
ReentrantLock的实现原理
读写锁 ReentrantReadWriteLock
synchronized 底层原理
Lock和synchronized的区别 乐观锁的底层原理 版本号机制 在数据库表中添加一个版本号字段如 version每次更新数据时都会将版本号加1。 当尝试更新数据时会检查当前版本号是否与开始操作时获取的版本号一致。 如果版本号一致则更新成功如果不一致则表示数据已被其他事务修改更新失败。 时间戳机制 类似于版本号机制但在表中使用时间戳字段来记录数据的最后修改时间。 更新数据时同样需要检查当前时间戳是否与开始操作时获取的时间戳一致。 如果时间戳一致则更新成功如果不一致则表示数据已被其他事务修改更新失败。 CAS 操作 CAS (Compare and Swap) 是一种无锁算法用于原子地更新一个变量的值。 在多线程环境中CAS 操作可以用来实现乐观锁。 CAS 操作通常由 CPU 提供硬件级别的支持也可以通过软件模拟实现。
乐观锁的优点 减少了锁的竞争提高了系统的吞吐量。 适用于读多写少的场景。
乐观锁的缺点 如果数据更新频繁可能导致更新失败的次数增多从而降低性能。 需要额外的字段存储版本号或时间戳 ReentrantLock的实现原理
ReentrantLock 是 Java 并发包java.util.concurrent.locks中提供的一个可重入互斥锁它提供了比 synchronized 关键字更灵活的锁机制。其核心实现原理基于 AbstractQueuedSynchronizerAQS框架
实现原理 可重入性ReentrantLock 允许同一个线程多次获取锁而不被阻塞通过内部维护一个计数器来记录锁被当前线程获取的次数。每次成功获取锁计数器加1每次释放锁计数器减1当计数器为0时其他线程才能获取到锁。 公平性与非公平性 公平锁FairSync按照请求锁的顺序来分配锁先来的线程优先获取锁。实现这一点需要维持一个先进先出FIFO的等待队列线程在尝试获取锁失败后会加入队列末尾等待。
非公平锁NonfairSync允许插队即当前线程尝试获取锁时即使有其他线程已经在等待队列中只要锁当前是空闲的就允许立即获取。这可以减少线程的上下文切换提高吞吐量但可能牺牲公平性。 自旋锁与AQSReentrantLock 在尝试获取锁时可能会使用自旋策略即线程在无法立即获取锁时不是立即挂起而是循环等待一段时间这尤其适用于锁持有时间很短的场景。AQS通过维护一个双向链表来管理等待线程链表中的每个节点代表一个等待状态的线程通过CAS操作来保证状态更新的原子性。 条件变量ReentrantLock 还支持条件变量Condition允许线程在满足特定条件前等待其他线程可以唤醒这些等待的线程。每个条件变量都有自己的等待队列。 锁的释放释放锁时不仅会减少锁的持有计数还会唤醒等待队列中的下一个线程如果有的话这通常通过LockSupport类的park/unpark方法实现。 读写锁 ReentrantReadWriteLock 读写锁的基本概念 读锁: 多个读操作可以同时进行不会互相阻塞。 写锁: 写操作是独占的在写操作进行时不允许任何读操作。 ReentrantReadWriteLock 的特点 可重入性: 同一个线程可以多次获取同一个锁。 公平性: 可以选择公平锁或非公平锁。 读写分离: 读操作和写操作分别使用不同的锁。 ReentrantReadWriteLock 的使用 创建锁: 通过 ReentrantReadWriteLock 类创建读写锁实例。 获取锁: 通过 readLock() 和 writeLock() 方法分别获取读锁和写锁。 锁定与解锁: 使用 lock() 和 unlock() 方法来锁定和解锁。 synchronized 底层原理
synchronized 关键字在 Java 中用于实现线程间的互斥和同步它基于 JVM 层面的监视器锁Monitor机制来实现。以下是 synchronized 的底层原理概述
1.对象头Object Header: Java 对象在内存中有一个对象头其中包含了对象的元数据如哈希码、GC代信息以及锁信息。 锁信息存储在一个称为 Monitor 的结构中这个结构是 JVM 提供的用来实现同步。 Monitor 监视器: 当一个线程试图进入一个由 synchronized 修饰的方法或代码块时它会尝试获取该对象的 Monitor 锁。 如果锁是可用的线程将进入临界区并且锁状态会变为“已锁定”。 如果锁已经被其他线程持有请求锁的线程将被阻塞直到锁被释放。
字节码指令: 在字节码级别synchronized 关键字会被转换为 monitorenter 和 monitorexit 指令。 monitorenter 指令会在执行前尝试获取锁而 monitorexit 指令则在执行后释放锁。 这些指令操作的是对象头中的 Monitor 结构。
锁升级: 为了提高性能JVM 实现了锁的升级机制。初始时锁可能处于无锁状态然后根据竞争情况升级为偏向锁、轻量级锁或重量级锁。 偏向锁适用于没有多个线程竞争的情况轻量级锁使用 CAS 操作尝试获取锁而重量级锁则涉及到操作系统级别的线程阻塞和唤醒。 即时编译优化: HotSpot VM 会对 synchronized 块进行优化例如如果检测到锁没有竞争它可以避免使用重量级锁从而减少上下文切换和线程调度的开销。
Lock和synchronized的区别 语法糖 vs 显式控制 synchronized: 是 Java 的关键字提供了语法级别的支持用于声明同步代码块或同步方法。 Lock: 是 java.util.concurrent.locks 包中的一个接口需要显式地获取和释放锁。 锁的获取与释放 synchronized: 在进入同步代码块或方法时自动获取锁并在退出时自动释放锁。 Lock: 需要显式地调用 lock() 方法获取锁并且必须在不再需要锁时显式地调用 unlock() 方法释放锁。为了防止因异常而导致锁未被释放通常将 unlock() 方法放在 finally 块中。 可重入性 synchronized: 具有可重入性允许同一个线程多次获取同一个锁。 Lock: 也支持可重入性但需要通过 ReentrantLock 类实现。 公平性 synchronized: 默认是非公平锁。 Lock: 可以通过 ReentrantLock 类的构造函数指定锁是否公平。 中断响应 synchronized: 无法响应中断请求即使线程被中断仍然持有锁。 Lock: 支持中断请求可以通过 tryLock 方法尝试获取锁并且可以监听中断信号。 锁状态的检查 synchronized: 无法检查锁是否被当前线程持有。 Lock: 可以通过 isHeldByCurrentThread() 方法检查当前线程是否持有锁。 等待/通知机制 synchronized: 直接使用 wait() 和 notify() 方法来实现线程间的等待/通知。 Lock: 通过 Condition 接口实现等待/通知机制需要与 Lock 结合使用。 异常处理 synchronized: 在发生异常时会自动释放锁因此不会出现死锁。 Lock: 发生异常时如果没有显式地释放锁可能会导致死锁。