app网站开发成功案例,免费发布出租房信息网站,域名注册成功怎么做网站,万网虚拟主机建网站转载自 一分钟理解Java公平锁与非公平锁 和朋友聊天他提到#xff1a;ReentrantLock 的构造函数可以传递一个 bool 数据#xff0c;true 时构造的是“公平锁”、false 时构造的是“非公平锁”。我的印象中锁是不区分类型的#xff0c;所以认为这应该是 Java 发明的概念ReentrantLock 的构造函数可以传递一个 bool 数据true 时构造的是“公平锁”、false 时构造的是“非公平锁”。我的印象中锁是不区分类型的所以认为这应该是 Java 发明的概念于是就恶补了一下。 锁的底层实现
无论什么语言在操作系统层面锁的操作都会变成系统调用System Call以 Linux 为例就是 futex 函数可以把它理解为两个函数 futex_wait(s)对变量 s 加锁futex_wake(s)释放 s 上的锁唤醒其他线程。 如果你熟悉操作系统原理其实就是 P/V 操作 Java 公平锁和非公平锁
公平锁的 lock 操作是调用futex_waitunlock 操作是调用futex_wake。比如下面的代码 非公平锁的 lock/unlock 操作会先做一次 CAS 操作然后再调用 futex_wait、futex_wake。比如下面的代码 在上锁之前增加了一个 CAS 原子操作它接受三个变量可以把它理解为下面的逻辑 第一个参数的值和第二个参数不相等则返回 0 表示操作失败否则更新为新的值。这个函数不是由代码实现的而是 CPU 提供的一个指令比如 Intel 的叫 cmpxchg高级语言进行了封装比如 Java 的 Atomic 变量。
为什么
明白了原理再来提问为什么在上锁之前先通过 CAS 修改一个变量表示“我要上锁”了看似很冗余的操作其实它是一次自旋如果资源很快被使用完可以提高系统的吞吐率。考虑下面的场景 上锁之前的时间是 t1上锁之后是 t2使用资源释放锁是 t3。现在有两个线程处于 t1 状态其中 A 线程先抢到资源处于 t2 B 线程也会尝试 lock与此同时 t2 释放了而 lock 动作也执行成功了 B 被挂起系统继续执行 A 释放成功唤醒 B 继续执行。上述过程中 B 只要再多等待“一丢丢”就不用被挂起直接获得资源继续执行。非公平锁的 CAS 操作就是为了增加一丢丢时间。
采用非公平锁如果系统中有 3 个线程执行A 抢到资源C 没有抢到处于挂起状态此时 B 尝试 CAS 操作而 A 刚好释放掉资源还没有来得及唤醒 C那么 B 会先抢到资源在 C 之前执行。这就是“非公平”的来历虽然 C 老老实实的等待了很长时间但是 B 的“时机”把握的好迅速“插队”完成资源抢占。
总结
上锁的过程本身也是有时间开销的如果操作资源的时间比上锁的时间还短建议使用非公平锁可以提高系统的吞吐率否则就老老实实的用公平锁。