0

我正在尝试为我的项目编写一些“游戏引擎”,但我遇到了线程问题。当我在主流中创建一个线程(LoadThread)时,它一直等到 Run(); 在 LoadThread 结束。

//loading thread
public class LoadThread implements Runnable{
    private boolean running = false;
    private Thread loader = null;

    public LoadThread(/*init data structures*/){
        loader = new Thread(this);
    }

    public void start(){
        running = true;
        run();
    }

    synchronized public void run() {
        System.out.println(" loading started ");
        while(running){            
            //do some loading, when done, running = false
        }
        System.out.println(" loading done ");
    }
}

//holds data, starts loading
public class SourceGod {
    private LoadThread img_loader;
    public void startLoading(){
        img_loader = new LoadThread(/* some data structures */);
        img_loader.start();
    }
}

//runs the game
public class Game extends GameThread implements ActionListener{
    private SourceGod sources;
    public Game(Window full_screen){
        sources = new SourceGod(/* some data structures */);
        System.out.println("before");
        sources.startLoading();
        System.out.println("after");
    }
}

//own thread to refresh
abstract public class GameThread extends JPanel implements Runnable{
    //anything from there is not called before "after"
}

输出

before
loading started
//some loaded data report, takes about 2-3s
loading done
after

任何帮助将不胜感激。(更多代码http://paste.pocoo.org/show/orCfn9a8yOeEQHiUrgjG/)谢谢,Vojtěch

4

2 回答 2

5

您的问题是您正在Thread构造函数中创建一个对象,但是当您调用时,start()您并没有启动线程,而是run()在同一个线程中运行该方法。这看起来混淆了扩展 Thread实施 Runnable

我认为你应该做的是:

// this should be of type Thread not LoadThread
private Thread img_loader;
...
// don't create the loader thread inside of LoadThread
img_loader = new Thread(new LoadThread(/* some data structures */));
img_loader.start();

LoadThreadRunnable是线程将要执行的类型的类。使用您当前的代码,当它调用时:

img_loader.start();

它实际上并没有启动一个新线程,它只是调用在同一个线程中调用的LoadThread.start()方法:run()

public void start(){
    running = true;
    run();
}

编辑:

在您提供的链接中更仔细地查看您发布的代码时,您正在构造函数中创建Thread对象LoadThread。这不是一个好的模式:

public LoadThread(/*init data structures*/) {
    // not recommended IMO
    loader = new Thread(this);
}

同样,当您调用时,LoadThread.start()您并没有启动线程,而是run()在同一个线程中调用。我会改用这种new Thread(new LoadThread())模式。如果您坚持包裹Thread 内部LoadThread那么您应该更改LoadThread.start()为:

// this should be removed, you want to call Thread.start() instead
public void start(){
    running = true;
    // this will start the internal thread which will call run()
    loader.start();
}

顺便说一句,如果您想running在另一个线程中设置为 false,则应将其标记为volatile.

于 2012-04-25T18:36:41.907 回答
0

使用 Runnable 接口的方式有几个问题:

  • runnable 是一种包装代码的方式,以便它可以在不同的线程中启动。您应该覆盖 run 方法。并且不要直接调用它,永远不会。
  • 要使用可运行对象,请包装到线程中并运行线程启动方法。因此,您不应覆盖线程的启动方法,或始终调用 super.start()。
  • 为可运行对象提供启动方法很麻烦。包装线程的 start 方法将在新线程(包装器)中调用 runnable 的 run 方法。就是这样。因此,如果您的可运行文件中有一个 start 方法,则包装线程将永远不会调用它。
  • 永远不要调用线程或可运行对象的运行方法。您会错过这一点,因为该方法将在当前线程中执行,而不是在新线程中执行。
  • 不要同步运行方法,它只打算由一个线程使用。

以下是您应该在您的情况下执行的操作:

//loading thread
public class LoadThread implements Runnable{
    /** Wether or not the thread is running. */
    private boolean running = false;
    /** Wrapper thread. */
    private Thread loader = null;

    public LoadThread(/*init data structures*/){
        loader = new Thread(this);
    }

    public void start(){
        running = true;
        loader.start();
    }

    @Override
    public void run() {
        System.out.println(" loading started ");
        while(running){            
            //do some loading, when done, running = false
        }
        System.out.println(" loading done ");
        running = false;
    }
}

如您所见,如果您想要一个启动方法,只需调用包装线程启动方法即可。

另外,如果您确实需要调用 start,请考虑不使用可运行对象,而是直接使用线程:

 //loading thread2
 public class LoadThread extends Thread{
    /** Wether or not the thread is running. */
    private boolean running = false;

    @Override
    public void run() {
        running = true;
        System.out.println(" loading started ");
        while(running){            
            //do some loading, when done, running = false
        }
        System.out.println(" loading done ");
        running = false;
    }
}

那要简单得多。

于 2012-04-25T18:46:43.437 回答