我有一个小应用程序,其具有一个渲染线程。所有这一切都还没有登录,是他们当前的位置画我的对象。

我有这样一些代码:

public void render()
{
    // ... rendering various objects

    if (mouseBall != null) mouseBall.draw()

}

然后我也有创建和设置mouseBall到一个新的球,当用户点击鼠标一些鼠标处理程序。然后,用户可以拖动鼠标和球会跟随在鼠标去。当用户释放球我有设置mouseBall = NULL另一鼠标事件。

但问题是,我的渲染循环运行速度不够快,在随机时间条件(mouseBall!= NULL)将返回true,但在分割点后,第二用户将让鼠标的去帮我会得到用于尝试.draw()一个空对象上的空指针异常。

什么是解决这样的?

的问题
有帮助吗?

解决方案

问题在于这样一个事实,你正在访问mouseBall两次,一次,以检查其是否不null和另一调用它的功能。可以通过使用临时这样避免此问题:

public void render()
{
    // ... rendering various objects
    tmpBall = mouseBall;
    if (tmpBall != null) tmpBall.draw();
}

其他提示

您有如果同步并绘制报表,使它们保证运行作为一个原子序列。在Java中,这将像这样进行:

    
public void render()
{
    // ... rendering various objects
    synchronized(this) {
        if (mouseBall != null) mouseBall .draw();
   }
}

我知道你已经接受了其他的答案,但第三个选择是使用java.util.concurrent.atomic包的的AtomicReference类。这提供了检索,更新和比较,原子行为没有你需要的任何支持代码操作。因此,在你的例子:

public void render()
{
    AtomicReference<MouseBallClass> mouseBall = ...;

    // ... rendering various objects
    MouseBall tmpBall = mouseBall.get();
    if (tmpBall != null) tmpBall.draw();
}

这看起来非常相似,格雷格的解决方案,并在概念上他们是在场景都使用波动背后相似,为了确保值的新鲜度,并采取临时副本,以便使用值之前,将条件。

因此这里所使用的确切的例子是不用于示出AtomicReferences的功率那么好。考虑而不是你的其他线程将更新mouseball vairable只有当它已经空 - 有用习惯的不同的代码初始化风情的街区。在这种情况下,通常会是必须使用同步,以确保如果你检查,发现球是零,它会的还是的为空当你试图将它(否则你回来了在您的原始问题的领域)。然而,随着的AtomicReference你可以简单地说:

mouseBall.compareAndSet(null, possibleNewBall);

,因为这是一个原子操作,因此,如果一个线程“看到”为空值它也将其设置为参考possibleNewBall之前的任何其他线程有机会读取它。

另一个不错的成语与原子引用是,如果你无条件地设置的东西,但需要与旧值执行某种清理。在这种情况下,可以说:

   MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
   // Cleanup code using oldBall

的AtomicIntegers有这些好处和更多;在getAndIncrement()方法是美妙的全局共享计数器你能保证每次调用它会返回一个不同的值,而不管线程的交织。线程安全与最小的麻烦。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top