A number of things jump out at me and scare me...
- You're not honoring the thread/Swing contract. All updates to the UI MUST be made from with the Event Dispatching Thread. All long running and blocking code should be executed in a background thread.
- Your "animation loop" is sucking up a lot of CPU time doing nothing. The thread should be sleeping between cycles (or at the very least, should only paint when something has changed), this should reduce the over all load on the system.
I tried a few solutions.
While I didn't have "significant" issues, these are really simple examples, I did generally get better performance with the default JVM options.
Buffering strategy
This is basically what you had, begin nice to the EDT and using the buffer strategy your were using
public class SimpleAnimationTest {
private boolean running = true;
private Rectangle box = new Rectangle(0, 90, 10, 10);
private int dx = 4;
protected static final int WIDTH = 200;
protected static final int HEIGHT = 200;
public static void main(String[] args) {
new SimpleAnimationTest();
}
public SimpleAnimationTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setIgnoreRepaint(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setSize(WIDTH, HEIGHT);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.createBufferStrategy(2);
final BufferStrategy bs = frame.getBufferStrategy();
new Thread(new Runnable() {
@Override
public void run() {
long tock = 1000 / 60;
while (running) {
box.x += dx;
if (box.x + box.width > WIDTH) {
box.x = WIDTH - box.width;
dx *= -1;
} else if (box.x < 0) {
box.x = 0;
dx *= -1;
}
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.WHITE);
g.fill(box);
g.dispose();
bs.show();
try {
Thread.sleep(tock);
} catch (InterruptedException ex) {
}
}
bs.dispose();
}
}).start();
}
});
}
}
Double Buffered Swing Components
public class SimpleAnimationTest {
private Rectangle box = new Rectangle(0, 90, 10, 10);
private int dx = 4;
public static void main(String[] args) {
new SimpleAnimationTest();
}
public SimpleAnimationTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new SimplePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SimplePane extends JPanel {
public SimplePane() {
setDoubleBuffered(true);
Timer timer = new Timer(1000 / 300, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
box.x += dx;
if (box.x + box.width > getWidth()) {
box.x = getWidth() - box.width;
dx *= -1;
} else if (box.x < 0) {
box.x = 0;
dx *= -1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
super.paintComponent(g2d);
box.y = (getHeight() - box.height) / 2;
g2d.setColor(Color.RED);
g2d.fill(box);
g2d.dispose();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}