Многопоточность: объекты, имеющие нулевое значение при их использовании - PullRequest
4 голосов
/ 14 декабря 2008

У меня есть небольшое приложение, в котором есть нить Render. Все, что делает эта нить, это рисует мои объекты в их текущем местоположении.

У меня есть код вроде:

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

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

}

Тогда у меня также есть некоторый обработчик мыши, который создает и устанавливает mouseBall в новый шар, когда пользователь щелкает мышью. Затем пользователь может перетащить мышь, и мяч будет следовать за тем, куда движется мышь. Когда пользователь отпускает мяч, у меня есть другое событие мыши, которое устанавливает mouseBall = null.

Проблема в том, что мой цикл рендеринга работает достаточно быстро, чтобы в произвольные моменты времени условное (mouseBall! = Null) возвращало значение true, но в эту долю секунды после этого момента пользователь отпустит мышь, и я получить исключение nullpointer для попытки .draw () на нулевом объекте.

Каково решение такой проблемы?

Ответы [ 3 ]

12 голосов
/ 14 декабря 2008

Проблема заключается в том, что вы обращаетесь к mouseBall дважды, один раз, чтобы проверить, не является ли он null, и другой, чтобы вызвать функцию для него. Вы можете избежать этой проблемы с помощью временного как это:

public void render()
{
    // ... rendering various objects
    tmpBall = mouseBall;
    if (tmpBall != null) tmpBall.draw();
}
8 голосов
/ 14 декабря 2008

Вы должны синхронизировать операторы if и draw так, чтобы они гарантированно выполнялись как одна атомарная последовательность. В Java это будет сделано так:

    
public void render()
{
    // ... rendering various objects
    synchronized(this) {
        if (mouseBall != null) mouseBall .draw();
   }
}
1 голос
/ 09 января 2009

Я знаю, что вы уже приняли другие ответы, но третьим вариантом будет использование класса AtomicReference пакета java.util.concurrent.atomic. Это обеспечивает операции поиска, обновления и сравнения, которые действуют атомарно, без необходимости какого-либо вспомогательного кода. Итак, в вашем примере:

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

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

Это выглядит очень похоже на решение Грега, и концептуально они похожи в том, что за кулисами оба используют волатильность, чтобы обеспечить свежесть значений, и делают временную копию для применения условия перед использованием значения.

Следовательно, точный пример, использованный здесь, не так хорош для демонстрации силы AtomicReferences. Вместо этого учтите, что ваш другой поток обновит переменную mouseball, только если она уже была нулевой - полезная идиома для различных блоков кода стиля инициализации. В этом случае обычно необходимо использовать синхронизацию, чтобы гарантировать, что если вы проверили и обнаружили, что шар был нулевым, он все еще будет нулевым, когда вы попытаетесь установить его (иначе вы вернетесь царства вашей первоначальной проблемы). Однако с AtomicReference вы можете просто сказать:

mouseBall.compareAndSet(null, possibleNewBall);

, потому что это атомарная операция, поэтому, если один поток «видит» значение как нулевое, он также установит для него ссылку возможногоNewBall, прежде чем другие потоки смогут его прочитать.

Еще одна приятная идиома с атомарными ссылками - если вы безоговорочно устанавливаете что-то, но должны выполнить какую-то очистку со старым значением. В этом случае вы можете сказать:

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

AtomicIntegers имеют эти преимущества и многое другое; Метод getAndIncrement () прекрасно подходит для глобально используемых счетчиков, поскольку вы можете гарантировать, что каждый вызов этого метода будет возвращать определенное значение, независимо от чередования потоков. Резьба безопасности с минимумом суеты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...