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

ところで、別のスレッドで false に設定したい場合は、runningとしてマークする必要がありますvolatile

于 2012-04-25T18:36:41.907 に答える
0

Runnable インターフェイスの使用方法にはいくつかの問題があります。

  • ランナブルは、別のスレッドで起動できるようにコードをラップする方法です。run メソッドをオーバーライドする必要があります。そして、それを直接呼び出さないでください。
  • ランナブルを使用するには、スレッドにラップし、スレッド開始メソッドを実行します。そのため、スレッドの start メソッドをオーバーライドしたり、常に super.start() を呼び出したりしないでください。
  • ランナブルに開始メソッドを提供するのは面倒です。ラッピング スレッドの start メソッドは、新しいスレッド (ラッパー スレッド) でランナブルの run メソッドを呼び出します。それでおしまい。そのため、ランナブルに start メソッドがある場合、それがラッピング スレッドによって呼び出されることはありません。
  • スレッドまたはランナブルの run メソッドを決して呼び出さないでください。メソッドが新しいスレッドではなく現在のスレッドで実行されるため、ポイントを見逃すことになります。
  • run メソッドを同期しないでください。既に 1 つのスレッドでのみ使用されることを意図しています。

あなたの場合にすべきことは次のとおりです。

//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 メソッドが必要な場合は、ラッパー スレッドの start メソッドを呼び出すだけです。

また、本当に 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 に答える