乐观锁 VS 悲观锁
乐观锁和悲观锁是两种处理并发访问的不同策略,用于确保多个操作不会同时修改同一资源而导致数据不一致的问题。它们的区别在于处理并发时的思想和实现方式:
乐观锁:
思想:认为在大多数情况下,读操作远远多于写操作,因此假设在绝大多数情况下并发冲突是不会发生的,直到出现实际冲突才会进行处理。
实现方式:通常使用版本号(Version)或时间戳(Timestamp)来实现。在读取数据时,会将版本号或时间戳一同读取并保存,在更新数据时,会比较更新前后的版本号或时间戳是否一致,如果一致则更新成功,否则更新失败需要进行重试或其他处理。
悲观锁:
思想:认为并发冲突是常态,因此在操作数据之前会先加锁,确保同一时间只有一个操作可以访问数据,其他操作需要等待。
实现方式:通常使用数据库的行级锁或者程序中的同步锁(如Java中的synchronized关键字)来实现。在读取或更新数据之前会先获取锁,操作完成后再释放锁。
总的来说,乐观锁适合读操作频繁、冲突概率低的场景,可以减少锁的竞争,提高并发性能;而悲观锁适合写操作频繁、冲突概率高的场景,可以确保数据的一致性。
无锁 VS 偏向锁 VS 轻量级锁 VS 重量级锁
在Java中,锁的升级过程包括从无锁状态到偏向锁、偏向锁到轻量级锁、轻量级锁到重量级锁的过程。以下是这些过程的简要描述:
无锁到偏向锁:
当一个线程第一次访问同步代码块时,会尝试获取偏向锁。
如果获取成功,则标记为偏向锁,锁的标记会指向获取偏向锁的线程ID。
如果获取失败,则表示有竞争,不会立即升级为偏向锁,而是会进入自旋锁或者直接升级为轻量级锁,具体取决于具体实现。
偏向锁到轻量级锁:
当有另一个线程尝试获取被偏向的锁时,会尝试升级为轻量级锁。
升级为轻量级锁时,使用CAS操作将对象头中的偏向锁标志位清除,并将锁的标记指向锁记录(Lock Record)的地址。
如果CAS操作失败,表示有竞争,则会进入自旋锁或直接升级为重量级锁。
轻量级锁到重量级锁:
当一个线程自旋等待轻量级锁的过程中,如果自旋超过一定的次数或者有其他线程尝试获取锁,则会升级为重量级锁。
升级为重量级锁时,会使用操作系统的互斥量来实现锁,将对象头中的标记置为指向重量级锁的指针,并阻塞当前线程,让其他线程竞争锁。
自旋锁:
在上述升级过程中,为了避免线程频繁地阻塞和唤醒,会使用自旋锁来在一定程度上减少线程的阻塞时间。
自旋锁会在尝试获取锁时,循环检查锁是否可用,避免线程阻塞。当自旋超过一定次数或者其他线程来竞争锁时,会放弃自旋,使用其他方式来处理。
可重入锁 VS 不可重入锁
可重入锁(Reentrant Lock)是指同一个线程在持有锁的情况下,可以重复地对同一个锁进行加锁操作而不会产生死锁。这种锁机制允许线程在持有锁的情况下多次进入同步代码块,而不会被自己持有的锁所阻塞。可重入锁的特点有助于简化编程模型,并提高了线程的灵活性和性能。
与之相对应,非可重入锁则不允许同一个线程在持有锁的情况下再次对同一个锁进行加锁操作,否则会导致死锁。
可重入锁通常使用一个计数器来记录当前线程持有锁的次数,当计数器为0时表示锁未被持有,可以被其他线程获取。
标签:重入,Java,思想,区别,线程,轻量级,自旋,操作,偏向 From: https://www.cnblogs.com/jietang64/p/18029962