您的位置 首页 java

java面试23讲6:多线程并发锁

六.Semaphore 信号量

Semaphore 是一种基于计数的信号量。它可以设定一个 阈值 ,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后, 线程 申请许可信号将会被阻塞。Semaphore 可以用来构建一些对象池,资源池之类的,比如 数据库连接池

实现互斥锁( 计数器 为 1)

我们也可以创建计数为 1 的 Semaphore,将其作为一种类似 互斥锁的机制 ,这也叫二元信号量,表示两种互斥状态。

代码实现

它的用法如下:

Semaphore 与 ReentrantLock

Semaphore 基本能完成 ReentrantLock 的所有工作,使用方法也与之类似,通过 acquire()与release()方法来获得和释放临界资源。经实测,Semaphone.acquire()方法默认为可响应中断锁,与 ReentrantLock.lockInterruptibly()作用效果一致,也就是说在等待临界资源的过程中可以被 Thread .interrupt()方法中断。此外,Semaphore 也实现了 可轮询的锁请求与定时锁的功能 ,除了方法名 tryAcquire 与 tryLock不同,其使用方法与 ReentrantLock 几乎一致。Semaphore 也提供了公平与非公平锁的机制,也可在构造函数中进行设定。Semaphore 的锁释放操作也由手动进行,因此与 ReentrantLock 一样,为避免线程因抛出异常而无法正常释放锁的情况发生,释放锁的操作也必须在 finally 代码块中完成。

七.AtomicInteger

首先说明,此处 AtomicInteger ,一个提供 原子操作 的 Integer 的类,常见的还有AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference 等,他们的实现原理相同,区别在与运算对象类型的不同。令人兴奋地,还可以通过 AtomicReference<V>将一个对象的所有操作转化成原子操作。我们知道, 多线程 程序中,诸如++i 或 i++等运算不具有原子性,是不安全的线程操作之一 。通常我们会使用 synchronized 将该操作变成一个原子操作,但 JVM 为此类操作特意提供了一些同步类,使得使用更方便,且使程序运行效率变得更高。通过相关资料显示,通常AtomicInteger的性能是 ReentantLock 的好几倍。

八.可重入锁(递归锁)

本文里面讲的是广义上的可重入锁,而不是单指 JAVA 下的 ReentrantLock。 可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层 递归函数 仍然有获取该锁的代码,但不受影响 。在 JAVA 环境下 ReentrantLock 和 synchronized 都是 可重入锁。

九.公平锁与非公平锁

公平锁(Fair)

加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得

非公平锁(Nonfair)

加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待

1. 非公平锁性能比公平锁高 5~10 倍,因为公平锁需要在多核的情况下维护一个队列

2. Java 中的 synchronized 是非公平锁,ReentrantLock 默认的 lock()方法采用的是非公平锁。

10. ReadWriteLock 读写锁

为了提高性能,Java 提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制 ,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率。 读写锁 分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由 jvm 自己控制的,你只要上好相应的锁即可。

读锁

如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁

写锁

如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!Java 中读写锁有个接口 java.util.concurrent.locks.ReadWriteLock ,也有具体的实现ReentrantReadWriteLock

11. 共享锁和独占锁

java 并发包提供的加锁模式分为独占锁和共享锁。

独占锁

独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock 就是以独占方式实现的互斥锁。独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。

共享锁

共享锁则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。共享锁则是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。

1. AQS 的内部类 Node 定义了两个常量 SHARED 和 EXCLUSIVE,他们分别标识 AQS 队列中等待线程的锁获取模式。

2. java 的并发包中提供了 ReadWriteLock,读-写锁。它允许一个资源可以被多个读操作访问,或者被一个 写操作访问,但两者不能同时进行。

文章来源:智云一二三科技

文章标题:java面试23讲6:多线程并发锁

文章地址:https://www.zhihuclub.com/194152.shtml

关于作者: 智云科技

热门文章

网站地图