在Java中,为什么我的多线程不能工作?

在Java中,为什么我的多线程不能工作?,java,multithreading,asynchronous,applet,graphics2d,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!")

起初我是这样做的:

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的事物的初始值设定项中。 但是,这不允许创建画布,也不允许创建画布中的小程序,因为线程实际上不是异步运行的。然后,我将“.start()”替换为“.run()”,线程只运行了一次,但SpaceCanvas初始化得非常完美


我做错了什么,如何修复?

我不确定这类代码的工作方式是否符合您的预期:

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

我认为你应该这样做:

Iterator iterator = players.iterator();
while (iterator.hasNext()) {
    iterator.next().update(fcount);
}
这同样适用于
实体
循环。更好的模式(从Java 5开始)是使用
for
循环:

for (Player player : players) {
    player.update(fcount);
}
此外,如果多个线程正在访问这些集合,它们必须以某种方式进行同步。您可以使用并发集合,也可以确保每个访问(读和写)都在
同步的
块中

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));
}

显然,
实体
需要以相同的方式进行
同步。

我不确定这类代码的工作方式是否符合您的预期:

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

我认为你应该这样做:

Iterator iterator = players.iterator();
while (iterator.hasNext()) {
    iterator.next().update(fcount);
}
这同样适用于
实体
循环。更好的模式(从Java 5开始)是使用
for
循环:

for (Player player : players) {
    player.update(fcount);
}
此外,如果多个线程正在访问这些集合,它们必须以某种方式进行同步。您可以使用并发集合,也可以确保每个访问(读和写)都在
同步的
块中

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));
}
显然,
实体
需要以相同的方式进行同步

  • 在这个千年中,使用Swing(
    JApplet/JPanel
    )而不是AWT(
    Applet/Canvas
  • 使用Swing时,建立一个Swing
    计时器,每隔500毫秒调用一次
    repaint()
  • (当使用Swing/
    定时器时
    )不要调用EDT(事件调度线程)上的
    线程。sleep(n)

  • …你能在一张纸上画画吗

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

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

    • 创建一个
      buffereImage
      ,大小与所需自定义图形的大小相同
    • 将图像添加到
      图像图标
    • 将图标添加到
      JLabel
    • 将标签添加到GUI
    • 在每个
      计时器上
      操作。
      • 调用
        image.getGraphics()
        以获取绘图表面
      • 复制您在
        paint()
        paintComponent()中可能执行的操作
        
      • (如果需要)删除所有以前的图形
      • 绘制当前自定义渲染
      • 图像的
        图形实例的
        dispose()
      • 调用
        label.repaint()
  • 在这个千年中,使用Swing(
    JApplet/JPanel
    )而不是AWT(
    Applet/Canvas
  • 使用Swing时,建立一个Swing
    计时器,每隔500毫秒调用一次
    repaint()
  • (当使用Swing/
    定时器时
    )不要调用EDT(事件调度线程)上的
    线程。sleep(n)

  • …你能在一张纸上画画吗

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

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

    • 创建一个
      buffereImage
      ,大小与所需自定义图形的大小相同
    • 将图像添加到
      图像图标
    • 将图标添加到
      JLabel
    • 将标签添加到GUI
    • 在每个
      计时器上
      操作。
      • 调用
        image.getGraphics()
        以获取绘图表面
      • 复制您在
        paint()
        paintComponent()中可能执行的操作
        
      • (如果需要)删除所有以前的图形
      • 绘制当前自定义渲染
      • 图像的
        图形实例的
        dispose()
      • 调用
        label.repaint()

    我很快就会试试这个,谢谢。还有,你能在JPanel上画画吗?你能在秋千上画些什么吗?我想使用画布,这样我可以在上面画画。这真的,真的很有用,(即使它没有解决我的问题),所以谢谢你让我保持在千年的编码标准之内!我很快就会试试这个,谢谢。还有,你能在JPanel上画画吗?你能在秋千上画些什么吗?我想使用画布,这样我可以在上面画画。这真的,真的很有用,(即使它没有解决我的问题),所以谢谢你让我保持在千年的编码标准之内!您还可以将
    用于(迭代器i=players.Iterator();i.hasNext();)