0

它们是如何实现的?我看过那个类的代码,它看起来不像任何类型的同步机制被用来确保线程安全或函数调用的原子性。

我指的是班级java.util.concurrent.Semaphore

编辑:请理解这绝不是错误报告或对 Java 技术的不信任。相反,请求让我理解。

4

2 回答 2

2

介绍

从更广泛的角度来看,问题变成了任何锁定机制如何实现螺纹安全。由于这个问题有几个部分,我将逐步进行。

比较和交换 (CAS)

比较和交换 (CAS)是机器级别的原子指令和程序级别的原子操作。现在,在您的特定信号量问题中,他们在从信号量访问许可时使用了这种技术。

  1. 获取当前值
  2. 计算新值
  3. 通过传入当前值新值执行CAS操作,查看该内存访问处的值是否为当前值并将其与新值交换。如果它确实保存了我们注意到的当前值,则该值存储在内存位置并返回 true。如果它找到与我们预期的当前值不同的值,它不会修改内存位置并返回 false。

AbstractQueuedSynchronizer

AbstractQueuedSynchronizer类是一个实现类,用于在获取许可时处理同步。该实现创建了一个FIFO 队列(尽管可以使用不同类型的队列)并利用park/unpark技术来处理线程运行状态。

停放/取消停放

当信号量中没有可用的许可时,线程将停止。相反,一旦许可可用,线程将unpark(假设您使用 FIFO 实现,第一个将unpark)并尝试CAS操作来获取许可。如果失败,它将停车并重复该过程。

结论

这些概念一起工作,通过机器级指令和编程操作利用原子性,以确保一次仅由单个线程获取许可/锁,从而将线程对逻辑块的访问限制在所需数量。

于 2018-08-17T13:38:06.593 回答
1

理解这一点的最佳方法是查看nonfairTryAcquireShared()

final int nonfairTryAcquireShared(int acquires) {
        for (;;) {
            int available = getState();
            int remaining = available - acquires;
            if (remaining < 0 ||
                compareAndSetState(available, remaining))
                return remaining;
        }
    }

所以,我们忙循环试图获取状态,然后我们试图接受它。

最有趣的部分在compareAndSetState()

protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

compareAndSwapInt是一个本机函数,它保证原子性,因此 - 在我们的例子中是同步的。

于 2018-08-17T11:44:21.643 回答