简体   繁体   English

在Java中,为什么我的多线程无法正常工作?

[英]In Java, why is my multithreading not working?

At first I did this: 首先,我这样做:

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

in the initializer of a thing I call a SpaceCanvas. 在事物的初始值设定项中,我称为SpaceCanvas。 However, that doesn't allow the canvas, and therefore the applet it is within, to be created, because the Thread doesn't actually run asynchronously. 但是,这不允许创建画布及其内部的applet,因为Thread 实际上并不异步运行。 Then, I replaced ".start()" with ".run()" and the thread only ran once, but the SpaceCanvas initialized perfectly. 然后,我将“ .start()”替换为“ .run()”,该线程只运行了一次,但SpaceCanvas初始化完美。

What did I do wrong, and how do I fix this? 我做错了什么,该如何解决?

I'm not sure this sort of code works the way you expect it to: 我不确定这种代码是否可以按您期望的方式工作:

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

players.iterator() gets a new iterator for the players collection. players.iterator()players集合获取一个新的迭代器。 If there are 0 items in the collection then it will be false but if there are any items, you will be in an infinite loop, creating a new iterator each time. 如果集合中有0个项目,那么它将为false但是如果有任何项目,您将处于无限循环中,每次都创建一个新的迭代器。 The iterator() call inside of players generates another new iterator object as well. players iterator()内部的iterator()调用也会生成另一个新的迭代器对象。

I think you should doing something like: 我认为您应该执行以下操作:

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

This is the same with your entities loop as well. entities循环也是如此。 A better pattern (as of Java 5) is to use the for loop: 更好的模式(从Java 5开始)是使用for循环:

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

Also, if multiple threads are accessing these collections, they have to be somehow synchronized . 另外,如果多个线程正在访问这些集合,则必须以某种方式synchronized You can either use a concurrent collection or you have to make sure every access (read and write) is within a synchronized block. 您可以使用并发集合,也可以确保每次访问(读取和写入)都在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));
}

Obviously the entities will need to be synchronized in the same manner. 显然, entities将需要以相同的方式进行synchronized

  1. In this millennium, use Swing ( JApplet/JPanel ) rather than AWT ( Applet/Canvas ) 在这个千年中,使用Swing( JApplet/JPanel )而不是AWT( Applet/Canvas
  2. When using Swing, establish a Swing Timer that calls repaint() every 500 msec. 使用Swing时,请建立一个Swing Timer ,每500毫秒调用一次repaint()
  3. (When using Swing/ Timer ) Don't call Thread.sleep(n) on the EDT (Event Dispatch Thread). (使用Swing / Timer )请勿在EDT(事件调度线程)上调用Thread.sleep(n) )。

..can you draw on a JPanel? ..您可以使用JPanel吗?

Sure thing. 当然可以 To do so, override the paintComponent(Graphics) method. 为此,请重写paintComponent(Graphics)方法。 You might also extend a JComponent and do the same, but there are some quirks to dealing with a JComponent that make the JPanel the better choice to extend. 您也可以扩展JComponent并执行相同的操作,但是处理JComponent会有一些怪癖,使JPanel成为扩展的更好选择。

On the other hand, there is another approach entirely. 另一方面,完全有另一种方法。

  • Create a BufferedImage of the size required for whatever custom graphic is needed. 创建所需的任何自定义图形所需大小的BufferedImage
  • Add the image to an ImageIcon . 将图像添加到ImageIcon
  • Add the icon to a JLabel . 将图标添加到JLabel
  • Add the label to the GUI. 将标签添加到GUI。
  • On each Timer action. 在每个Timer动作上。
    • Call image.getGraphics() to obtain the drawing surface. 调用image.getGraphics()获得绘图表面。
    • Replicate what you might have done in paint() or paintComponent() 复制您可能在paint()paintComponent()所做的工作
      1. (If needed) erase all previous drawing. (如果需要)删除所有先前的图形。
      2. Draw the current custom rendering. 绘制当前的自定义渲染。
    • dispose() of the Graphics instance of the image. 图像的Graphics实例的dispose()
    • call label.repaint() 调用label.repaint()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM