Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程:对象在使用时被设置为null_Java_Multithreading_Nullpointerexception - Fatal编程技术网

Java 多线程:对象在使用时被设置为null

Java 多线程:对象在使用时被设置为null,java,multithreading,nullpointerexception,Java,Multithreading,Nullpointerexception,我有一个小应用程序,它有一个渲染线程。该线程所做的就是在对象的当前位置绘制对象 我有一些代码,比如: public void render() { // ... rendering various objects if (mouseBall != null) mouseBall.draw() } 然后,我还有一些鼠标处理程序,当用户单击鼠标时,可以创建并将鼠标球设置为新球。然后,用户可以拖动鼠标,球将跟随鼠标移动的方向。当用户释放球时,我有另一个鼠标事件,它将mouseBa

我有一个小应用程序,它有一个渲染线程。该线程所做的就是在对象的当前位置绘制对象

我有一些代码,比如:

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

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

}
然后,我还有一些鼠标处理程序,当用户单击鼠标时,可以创建并将鼠标球设置为新球。然后,用户可以拖动鼠标,球将跟随鼠标移动的方向。当用户释放球时,我有另一个鼠标事件,它将mouseBall设置为null

问题是,我的渲染循环运行得足够快,在随机时间条件(mouseBall!=null)将返回true,但在该时间点后的那一瞬间,用户将放开鼠标,我将得到一个null指针异常,因为我尝试对null对象执行.draw()


这样一个问题的解决方案是什么?

问题在于,您要访问
鼠标球两次,一次检查它是否为空,另一次调用它的函数。您可以使用以下临时方法来避免此问题:

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

您必须同步if和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();
}
因为这是一个原子操作,所以如果一个线程“看到”该值为null,它也会在其他线程有机会读取它之前将其设置为possibleNewBall引用

原子引用的另一个好习惯用法是,如果您正在无条件地设置某些内容,但需要使用旧值执行某种清理。在这种情况下,你可以说:

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

原子整数有这些好处和更多;getAndIncrement()方法对于全局共享计数器非常有用,因为您可以保证对它的每次调用都将返回一个不同的值,而不考虑线程的交错。螺纹安全,无需担心。

完全正确。如果要在没有同步块的情况下执行此操作,请确保mouseBall是易失性的。这会在mouseBall.draw()方法调用的整个过程中一直保持对“this”的锁定,这可能比保持锁定所需的时间要长。此外,只有当对鼠标球的所有其他访问(读写)也被同步(this){…}块包围时,这才是原子的。
   MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
   // Cleanup code using oldBall