4

我已经稍微提炼了这个问题,消除了我的一些理解,试图让它像 poss 一样简洁和具体,所以它可能看起来很基本

我应该如何使用 AtomicInteger 作为参考计数器来管理某些资源的清理但以安全和原子的方式?

例如:

1)香草示例:

public void close() {
    if ((refCt.decrementAndGet()) == 0) {
        DBUtil.close(conn);             
    }
}

这一切都很好, refCt 本身是原子的,但值可能会以关闭资源不会关闭的方式发生变化 - 例如,另一个线程在条件之前减少计数。

使用 var(线程中的堆栈)可以确保在我的线程中维护 refCt,我猜但是

2)矫枉过正(?)示例:

public void close() {
    synchronized(lock) {
        if ((refCt.decrementAndGet()) == 0) {
            DBUtil.close(conn);             
        }
    }
}

我的 refCt 本身是原子的,我对条件(在 AtomicInteger 外部)的测试与保障原子性同步。

3)我是否应该实际使用AtomicInteger自身来管理条件通过#compareAndSet并避免阻塞?

public void close() {
    for (;;) {
        int current = refCt.get();
        int refCtDec = current - 1;
        if (compareAndSet(current, refCtDec))
            DBUtil.close(conn);             
    }
}

4)这一切是否比应有的复杂/我不能只见树木不见森林吗?

4

2 回答 2

3

不幸的是,只有 AtomicInteger 对您没有帮助,所以 1 和 3 都出局了。考虑这种情况:

  1. 线程 1 使用资源并完成它。
  2. 进入 If 语句,发现没有其他线程正在使用它,并将计数器(原子地)递减为 0
  3. 调度程序启动线程 2,增加计数器并开始使用资源
  4. 线程 1 唤醒并关闭资源
  5. 线程 2 无缘无故关闭了连接。

需要一个显式锁来使更改计数器和关闭伪原子操作(即,如果不获取锁就不能更改计数器)。在那种情况下,您不需要 Integer 是原子的。

然而,这看起来像是糟糕的设计——用 Java 编写的 C 代码,永远不会有好的结局(反过来也很丑陋)。我会考虑改变线程之间共享资源的方式。

于 2014-04-17T15:39:32.250 回答
1

这一切都很好,refCt 本身是原子的,但是值可能会以这样的方式发生变化,即关闭资源不会被关闭 - 例如,另一个线程在条件之前减少计数。

AtomicIntegeris (就像它的名字一样)是完全原子的。该方法decrementAndGet()看起来像 2 次操作,但事实并非如此。只有一个线程会看到减量AtomicInteger为 0。唯一的问题是如果你在其他地方减量。

另一种可能性是线程一直在递增然后递减。因此,可能存在一些问题,DBUtil即关闭但必须再次打开或其他什么。然后你可能需要一个锁,但锁只能在调用周围而DBUtil不是递减AtomicInteger

2)矫枉过正(?)示例:

是的,我想是这样。除非需要锁来控制对DBUtil.

3)我是否应该实际使用 AtomicInteger 本身通过#compareAndSet 管理条件并避免阻塞?

我认为没有必要这样做。在内部AtomicInteger处理递减的竞争条件。这是代码decrementAndGet()

    for (;;) {
        int current = get();
        int next = current - 1;
        if (compareAndSet(current, next))
            return next;
    }

4)这一切是否比应有的复杂/我不能只见树木不见森林吗?

看上面。

于 2014-04-17T15:26:58.183 回答