Swing はシングルスレッド環境です。UI の状態を定期的に変更する場合は注意が必要です。イベント ディスパッチ スレッドをブロックしないようにする必要があります。ブロックすると、新しいペイント イベント (とりわけ) が処理されなくなり、UI がハングしたように見えます。イベントディスパッチスレッドで更新して、競合状態やその他のスレッドの問題の危険を冒さないようにします
詳細については、Swing での同時実行を詳しく見てください。簡単なアプローチは、たとえばSwing Timerを使用することです...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Spinner {
public static void main(String[] args) {
new Spinner();
}
public Spinner() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SpinnerPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SpinnerPane extends JPanel {
private float angle;
public SpinnerPane() {
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
angle -= 5;
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(40, 40);
}
protected Point calculateOutterPoint(float angel) {
int radius = Math.min(getWidth(), getHeight());
int x = Math.round(radius / 2);
int y = Math.round(radius / 2);
double rads = Math.toRadians((angel + 90));
// This determins the length of tick as calculate from the center of
// the circle. The original code from which this derived allowed
// for a varible length line from the center of the cirlce, we
// actually want the opposite, so we calculate the outter limit first
int fullLength = Math.round((radius / 2f)) - 4;
// Calculate the outter point of the line
int xPosy = Math.round((float) (x + Math.cos(rads) * fullLength));
int yPosy = Math.round((float) (y - Math.sin(rads) * fullLength));
return new Point(xPosy, yPosy);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
int diameter = Math.min(getWidth(), getHeight());
int x = (getWidth() - diameter) / 2;
int y = (getHeight() - diameter) / 2;
Point to = calculateOutterPoint(angle);
g2d.drawLine(x + (diameter / 2), y + (diameter / 2), x + to.x, y + to.y);
g2d.dispose();
}
}
}
同様のメカニズムを使用して、次のような待機アニメーションを作成できました...

