3

ループ内でのスレッドの使用について広範な検索を行いましたが、個別のスレッドがどのように機能するかという概念は理解していますが、単純なアプリケーションでそれを実装する方法をまだ把握できていないようです。

私のアプリケーションは、テキスト ボックスのあるフォームで構成されています。このテキストボックスは、ループの反復ごとに更新する必要があります。ボタンを押すとループが始まりますが、停止ボタンを押すとループも終了します。ブール値を使用して、押されたかどうかを追跡しました。

ここに私のフォームコードがあります:

package threadtester;

public class MainForm extends javax.swing.JFrame {

    public MainForm() {
        initComponents();
    }

    private void RunButtonActionPerformed(java.awt.event.ActionEvent evt) {
       ThreadTester.setRunnable(true);
       ThreadTester example = new ThreadTester(2,this);
       example.run();
    }

    private void StopButtonActionPerformed(java.awt.event.ActionEvent evt) {
       ThreadTester.setRunnable(false);
    }


    public static void main(String args[]) {

    java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MainForm().setVisible(true);
            }
        });
    }

    public void setTextBox(String myString){
    MainTextbox.setText(myString);
    }

}

ご覧のとおり、押されたボタンがあります。ボタンが押されると、ThreadTester という別のクラスにあるコードが実行されます。そのクラスのコードは次のとおりです。

package threadtester;

import java.util.logging.Level;
import java.util.logging.Logger;

public class ThreadTester implements Runnable
{
    int thisThread;
    MainForm myMainForm;
    private static boolean runnable;
    // constructor
    public ThreadTester (int number,MainForm mainForm)
    {
        thisThread = number;
        myMainForm = mainForm;   
    }

    public void run ()
    {
    for (int i =0;i< 20; i++) {
        if(runnable==false){
           break;
        } 
        System.out.println("I'm in thread " + thisThread + " line " + i);
        myMainForm.setTextBox(i + "counter");
        try {
               Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(ThreadTester.class.getName()).log(Level.SEVERE, null, ex);
        }
    } }

    public static void setRunnable(Boolean myValue){
       runnable = myValue;
    }

    public static void main(String[] args) {

        MainForm.main(args);
    }  
}

ご覧のとおり、ループは別のスレッドで作成されています...しかし、テキストボックスはループが終了した後にのみ更新されます。MainForm で認識している限り、ループを実行するための別のスレッドを作成したので、実行されていない理由がわかりませんか? スタック交換の例を調べてみましたが、実装に適合させることができないようです。

Tassos によって提案された推奨事項により、私の run メソッドは次のようになります。

public void run ()
{
for (int i =0;i< 20; i++) {
    if(runnable==false){
        break;
    }
    System.out.println("I'm in thread " + thisThread + " line " + i);

    final String var = i + "counter";
        java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
                myMainForm.setTextBox(var);
        }
    });


    try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(ThreadTester.class.getName()).log(Level.SEVERE, null, ex);
        }
} }
4

3 に答える 3

3

この行を変更

    myMainForm.setTextBox(i + "counter");

の中へ

final String var = i + "counter";
java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
                    myMainForm.setTextBox(var);
        }
    });
}

なんで?非 UI スレッドでは UI 作業を行うことができないためです。

于 2013-06-14T11:54:43.417 に答える
3

タソスの答えが機能するためには、実際には新しいスレッドを作成する必要がありますが、作成していません。単に呼び出す

ThreadTester example = new ThreadTester(2,this);
example.run();

runEDT からメソッドを呼び出すだけでは十分ではありません。次のことを行う必要があります。

Thread t = new Thread(new ThreadTester(2,this));
t.start();

スレッドの定義と開始を参照してください。

また、2 つの異なるスレッド ( runnable) から同じフィールドを変更する必要がありますが、これはバグです。Java の並行性について詳しく読む必要があります。

于 2013-06-14T13:17:39.130 に答える
3

問題は、EDT (イベント ディスパッチ スレッド) をブロックしているため、ループが終了するまで UI が更新されないことです。

これらの問題の解決策は常に同じで、Swing をTimer使用するか、SwingWorker.

a の使用例を次に示しますSwingWorker

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class TestSwingWorker {

    private JTextField progressTextField;

    protected void initUI() {
        final JFrame frame = new JFrame();
        frame.setTitle(TestSwingWorker.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton("Clik me to start work");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                doWork();
            }
        });
        progressTextField = new JTextField(25);
        progressTextField.setEditable(false);
        frame.add(progressTextField, BorderLayout.NORTH);
        frame.add(button, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }

    protected void doWork() {
        SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
            @Override
            protected Void doInBackground() throws Exception {
                // Here not in the EDT
                for (int i = 0; i < 100; i++) {
                    // Simulates work
                    Thread.sleep(10);
                    publish(i); // published values are passed to the #process(List) method
                }
                return null;
            }

            @Override
            protected void process(List<Integer> chunks) {
                // chunks are values retrieved from #publish()
                // Here we are on the EDT and can safely update the UI
                progressTextField.setText(chunks.get(chunks.size() - 1).toString());
            }

            @Override
            protected void done() {
                // Invoked when the SwingWorker has finished
                // We are on the EDT, we can safely update the UI
                progressTextField.setText("Done");
            }
        };
        worker.execute();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestSwingWorker().initUI();
            }
        });
    }
}
于 2013-06-14T13:06:30.250 に答える