我已经对这个问题进行了一些改进,删除了我的一些理解,尝试使其尽可能简洁明了,因此它可能会被认为是非常基本的
我应该如何使用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)这是否比它应该更复杂/我不能看到树木的木材?
答案 0 :(得分:3)
不幸的是,只有AtomicInteger不会帮助你,所以1和3都不在。考虑这种情况:
需要显式锁定以使计数器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)这是否比它应该更复杂/我不能看到树木的木材?
见上文。