在Java中,为什么我的多线程不起作用?

时间:2012-05-04 22:19:03

标签: java multithreading asynchronous applet graphics2d

起初我这样做了:

public SpaceCanvas(){
    new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
        int fcount = 0;

        @Override
        public void run() {
                System.out.println("Update thread started!");
                while(!Thread.interrupted()){
                    fcount++;
                    while(players.iterator().hasNext()){
                        players.iterator().next().update(fcount);
                    }
                    while(entities.iterator().hasNext()){
                        entities.iterator().next().update(fcount);
                    }
                    System.out.println("About to paint");
                    repaint();
                    System.out.println("Done with paints");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
        }
    }).start();
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

在我称之为SpaceCanvas的东西的初始化器中。 但是,这不允许创建画布,因此创建它所在的applet,因为Thread不会实际异步运行。然后,我用“.run()”替换了“.start()”,线程只运行了一次,但SpaceCanvas完全初始化。

我做错了什么,我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

我不确定这种代码是否按预期方式运行:

while(players.iterator().hasNext()){
    players.iterator().next().update(fcount);

players.iterator()获取players集合的新迭代器。如果集合中有0个项目,那么它将是false但如果有任何项目,您将处于无限循环中,每次都创建一个新的迭代器。 iterator()内的players调用也会生成另一个新的迭代器对象。

我认为你应该这样做:

Iterator iterator = players.iterator();
while (iterator.hasNext()) {
    iterator.next().update(fcount);
}

这也与您的entities循环相同。更好的模式(从Java 5开始)是使用for循环:

for (Player player : players) {
    player.update(fcount);
}

此外,如果多个线程正在访问这些集合,则它们必须以某种方式synchronized。您可以使用并发集合,也可以确保每个访问(读取和写入)都在synchronized块内。

synchronized (players) {
    for (Player player : players) {
        player.update(fcount);
    }
}
...
// down in the outer thread
synchronized (players) {
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

显然,entities必须以同样的方式synchronized

答案 1 :(得分:1)

  1. 在这个千禧年,使用Swing(JApplet/JPanel)而不是AWT(Applet/Canvas
  2. 使用Swing时,建立一个每500毫秒调用Timer的Swing repaint()
  3. (使用Swing / Timer时)请勿在EDT(事件调度线程)上调用Thread.sleep(n)

  4.   

    ..你可以在JPanel上画画吗?

    当然可以。为此,请覆盖paintComponent(Graphics)方法。您也可以扩展JComponent并执行相同的操作,但是处理JComponent会有一些怪癖,这使得JPanel成为更好的扩展选择。

    另一方面,完全有另一种方法。

    • 创建所需大小所需的BufferedImage
    • 将图片添加到ImageIcon
    • 将图标添加到JLabel
    • 将标签添加到GUI。
    • 每个Timer行动。
      • 致电image.getGraphics()以获取绘图表面。
      • 复制您在paint()paintComponent()中所做的工作
        1. (如果需要)擦除之前的所有图纸。
        2. 绘制当前的自定义渲染。
      • dispose() Graphics图片实例。
      • 致电label.repaint()