我知道您已经接受了其他答案,但第三个选项是使用java.util.concurrent.atomic包中的AtomicReference类。它提供了检索、更新和比较操作,这些操作在不需要任何支持代码的情况下可以原子方式执行。因此,在您的示例中:
public void render()
{
AtomicReference<MouseBallClass> mouseBall = ...;
MouseBall tmpBall = mouseBall.get();
if (tmpBall != null) tmpBall.draw();
}
这看起来与Greg的解决方案非常相似,从概念上讲,它们都使用波动性来确保值的新鲜度,并在使用值之前复制临时副本以应用条件。
因此,这里使用的确切示例并不是展示AtomicReferences强大的好例子。相反,考虑您的另一个线程仅在mouseball变量已经为null时才更新 - 这是各种初始化样式代码块的有用惯用语法。在这种情况下,通常必须使用同步来确保如果您检查并发现球为空,则在尝试设置它时它仍将为空(否则您将回到原始问题的领域)。但是,使用AtomicReference,您只需简单地说:
mouseBall.compareAndSet(null, possibleNewBall);
由于这是一项原子操作,因此如果一个线程将值视为null,则它也会在其他线程有机会读取它之前将其设置为possibleNewBall引用。
使用原子引用的另一个好习惯是,如果您无条件地设置某些内容但需要执行旧值的某种清理,则可以使用以下语法:
MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
// Cleanup code using oldBall
AtomicInteger有许多好处,其中getAndIncrement()方法非常适用于全局共享计数器,因为你可以保证每次调用它都会返回一个不同的值,无论线程之间的交错如何。轻松实现线程安全。