Необходимо обновить графический интерфейс на EDT, чтобы убедиться, что рисование выполнено правильно. Прочитайте раздел из учебника по Swing по Concurrency для полного объяснения этой концепции.
Когда вы используете Swing Timer, событие выполняется в EDT, поэтому вы можете просто указать компоненту перекрасить себя в новом месте.
Когда вы используете Thread, зацикливание завершается вне EDT, и вам нужно использовать SwingUtilities.invokeLater (...), чтобы поместить код рисования обратно в EDT.
В общем, если вы кодируете, просто перемещая компонент из одного места в другое, то, вероятно, проще всего использовать таймер. Однако, если ваша игра включает в себя много сложной логики, вы не хотите, чтобы эта логика выполнялась в EDT, поскольку она будет препятствовать тому, чтобы GUI реагировал на события и перерисовывал себя. В этом случае вы можете использовать поток.