Java锁的类型有哪些(新手必看)
在 Java 中,锁是一种同步机制,用于控制多个线程访问共享资源的顺序,其目的是防止多个线程在同一时间对同一资源进行读写,从而避免数据不一致或者数据损坏的问题。
在没有锁的情况下,如果两个线程同时修改同一份数据,可能会导致数据不一致的情况,这被称为数据竞争。通过使用锁,我们可以保证当一个线程需要访问一个被其他线程占用的资源时,这个线程会被阻塞,直到锁被释放。通过这种方式,锁确保了同一时间只有一个线程可以修改共享资源,从而避免了数据竞争。
Java 锁提供了两个主要特性,分别是互斥性和可见性:
在 Java 中,相信大家听说过很多锁,例如乐观锁、悲观锁、读写锁、可重入锁等。锁的种类众多,容易让人混淆,其实这是按照不同的标准对锁进行分类造成的,以下是一些常见的锁分类。
1) 按照锁的实现方式分类:
2) 按照锁的特性分类:
3) 按照锁的访问方式分类:
4) 按照锁的获取方式分类:
5) 按照锁的作用范围分类:
不同类型的锁适用于不同的并发场景。在选择适当的锁类型时,需要权衡性能、易用性、特性和需求等多方面因素。
在没有锁的情况下,如果两个线程同时修改同一份数据,可能会导致数据不一致的情况,这被称为数据竞争。通过使用锁,我们可以保证当一个线程需要访问一个被其他线程占用的资源时,这个线程会被阻塞,直到锁被释放。通过这种方式,锁确保了同一时间只有一个线程可以修改共享资源,从而避免了数据竞争。
Java 锁提供了两个主要特性,分别是互斥性和可见性:
- 互斥性:互斥性意味着在同一时间内,只有一个线程可以获取锁。这就确保了在任何时候,只有一个线程可以执行被锁保护的代码区域,从而避免了并发冲突;
- 可见性:可见性是指当一个线程释放锁时,它所做的更改将对接下来获得那个锁的其他线程可见。这确保了线程之间对共享资源的更改能被正确地看到。
在 Java 中,相信大家听说过很多锁,例如乐观锁、悲观锁、读写锁、可重入锁等。锁的种类众多,容易让人混淆,其实这是按照不同的标准对锁进行分类造成的,以下是一些常见的锁分类。
1) 按照锁的实现方式分类:
- 内置锁(Intrinsic Lock):也称为监视器锁,是通过 synchronized 关键字隐式实现的;
- 显式锁(Explicit Lock):在 java.util.concurrent.locks 包中定义,如 Reentrant-Lock、ReadWriteLock、StampedLock 等,需要显式地创建、获取锁和释放锁。
2) 按照锁的特性分类:
- 可重入锁(Reentrant Lock):允许线程重复获取已经获取的锁。Reent-rantLock 和 synchronized 块都是可重入锁;
- 读写锁(Read-Write Lock):分为读锁和写锁,允许多个线程同时读取,但只允许一个线程写入;
- 乐观锁/悲观锁(Optimistic/Pessimistic Lock):乐观锁通常不会立即锁定资源,而是在提交操作时检查资源是否被修改;悲观锁则在操作资源之前直接锁定;
- 公平锁/非公平锁(Fair/Nonfair Lock):公平锁按照线程请求锁的顺序授予锁,而非公平锁则可能“插队”;
- 分段锁(Segmented Lock):在数据结构中使用,将结构分割成若干部分,每部分使用单独的锁。
3) 按照锁的访问方式分类:
- 独享锁(Exclusive Lock):一次只允许一个线程获取锁,例如 ReentrantLock;
- 共享锁(Shared Lock):允许多个线程同时获取锁,例如 ReadWriteLock 中的读锁。
4) 按照锁的获取方式分类:
- 阻塞锁(Blocking Lock):当锁不可用时,线程将被阻塞,直到锁被释放;
- 非阻塞锁(Non-blocking Lock):如通过 CAS 操作实现的锁,线程尝试通过原子操作获取锁,失败则立即返回或重试;
- 自旋锁(Spin Lock):线程反复检查锁是否可用,而不是进入阻塞状态。
5) 按照锁的作用范围分类:
- 对象级锁(Object-Level Lock):锁定单个对象实例,常通过 synchronized 关键字和 ReentrantLock 实现;
- 类级锁(Class-Level Lock):锁定类的 Class 对象,通常用于静态方法或静态字段,可以通过 synchronized 关键字和 static 修饰符来实现。
不同类型的锁适用于不同的并发场景。在选择适当的锁类型时,需要权衡性能、易用性、特性和需求等多方面因素。