I am just toying around with the idea of creating a multithreaded renderer in swing for my java2d games where each thread is responsible for rendering its own swingcomponent and came up with a simple program to try and and achieve this.
*I am aware that Thread.sleep is not the preferred method but it has worked without a hitch on my single-threaded renderings that use active rendering, I haven't tested with a swingtimer but to my knowledge Thread.sleep sleeps the calling thread so that cannot be the issue.
(Problem) The program creates four panels in four threads with a bouncing ball in each but only the first created thread ever does anything, the others are simply not started at all (verifiable with sysout in run methods). So only one thread does the rendering, the others are never given a chance to run, the sysout: System.out.println("Ballbouncer: " + this + " running.");
confirms this and so does the visual (image added).
BallBouncer (runnable)
public class BallBouncer implements Runnable {
private ColoredPanel ballContainer;
private List<Ellipse2D.Double> balls;
public static final Random rnd = new Random();
private double speedX, speedY;
public BallBouncer(ColoredPanel container) {
this.ballContainer = container;
this.balls = new ArrayList<>();
balls.add(container.getBall());
this.speedX = 10 * rnd.nextDouble() - 5;
this.speedY = 10 * rnd.nextDouble() - 5;
}
public BallBouncer(List<ColoredPanel> containers) {
for (ColoredPanel p : containers) {
new BallBouncer(p).run();
}
}
@Override
public void run() {
while (true) {
System.out.println("Ballbouncer: " + this + " running.");
moveBall();
ballContainer.repaint();
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void moveBall() {
for (Ellipse2D.Double ball : balls) {
ball.x += speedX;
ball.y += speedY;
if (ball.x < 0
|| ball.x + ball.getWidth() > ballContainer.getWidth()) {
speedX *= -1;
}
if (ball.y < 0
|| ball.y + ball.getHeight() > ballContainer.getHeight()) {
speedY *= -1;
}
}
}
Container
public class ColoredPanel extends JPanel {
private Ellipse2D.Double circle;
public ColoredPanel(Color color) {
circle = new Ellipse2D.Double(0, 0, 10, 10);
setBackground(color);
}
public Ellipse2D.Double getCircle() {
return circle;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getBackground().darker());
g2d.fill(circle);
}
@Override
@Transient
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public Double getBall() {
return getCircle();
}
Main
public class ColoredPanelContainer extends JPanel {
private List<ColoredPanel> panels = new ArrayList<>();
public ColoredPanelContainer() {
setUpPanels();
setBackground(Color.black);
}
private void setUpPanels() {
for (int i = 0; i < 4; i++) {
Color color = new Color(BallBouncer.rnd.nextInt(256),
BallBouncer.rnd.nextInt(256), BallBouncer.rnd.nextInt(256));
panels.add(new ColoredPanel(color));
}
for (int i = 0; i < 4; i++) {
add(panels.get(i));
}
}
@Override
@Transient
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
public List<ColoredPanel> getPanels() {
return panels;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
ColoredPanelContainer container = new ColoredPanelContainer();
frame.getContentPane().add(container);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
new BallBouncer(container.getPanels());
}
}
Notice the ball only bouncing in the left panel (first started thread), the others are stationary at all times.