我应该如何使用AtomicInteger作为参考计数器来管理某些资源?

时间:2014-04-17 15:22:13

标签: java multithreading concurrency atomicinteger

我已经对这个问题进行了一些改进,删除了我的一些理解,尝试使其尽可能简洁明了,因此它可能会被认为是非常基本的

我应该如何使用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外部)的测试与safeguar原子性同步。

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

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

4)这是否比它应该更复杂/我不能看到树木的木材?

2 个答案:

答案 0 :(得分:3)

不幸的是,只有AtomicInteger不会帮助你,所以1和3都不在。考虑这种情况:

  1. 线程1使用资源并完成它。
  2. 进入If语句,看到没有其他线程正在使用它并将计数器(原子地)递减为0
  3. 计划程序启动线程2,增加计数器并开始使用资源
  4. 线程1唤醒并关闭资源
  5. 线程2无缘无故地关闭连接。
  6. 需要显式锁定以使计数器AND关闭伪原子操作(即,在不获取锁定的情况下不能更改计数器)。在那种情况下,您不需要整数是原子的。

    这看起来像糟糕的设计 - 用Java编写的C代码,它永远不会结束(反之亦然)。我会考虑改变线程之间共享资源的方式。

答案 1 :(得分:1)

  

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

AtomicInteger(就像它的名字一样)是完全原子的。方法decrementAndGet()似乎是2个操作,但事实并非如此。只有一个线程会将递减的AtomicInteger视为0.唯一的问题是如果你在其他地方递减它。

另一种可能性是线程在所有时间都在递增然后递减。因此可能存在DBUtil正在关闭但随后必须再次打开的问题。然后,您可能需要锁定,但锁定可以在DBUtil调用附近,而不是 AtomicInteger减少。

  

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

是的,我想是的。除非需要锁定来控制对DBUtil的访问权限,否则您不应该需要锁定。

  

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

我认为没有必要这样做。在内部,AtomicInteger负责减少竞争条件。这是decrementAndGet()的代码:

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

4)这是否比它应该更复杂/我不能看到树木的木材?

见上文。