1

実装の詳細: 私はいくつかのキューをシミュレートする必要がある学校のプロジェクトに取り組んでいます。ランダムな間隔で、クライアントを生成する必要があり、クライアントは入力する 1 つのキュー (複数のキューを持つことができます) を選択し、そのキュー データ構造に追加されます。各キューには、アタッチされているキューからクライアントを削除する独自のオペレーターがあります。

問題: クライアント ジェネレーターは別のスレッドで実行されます。キューのグラフィカルな表現は、GridLayout パネルに表示される JButton の ArrayList の表現であり、1 列しかありません。クライアント (JButton) をパネルに追加しようとすると、SwingWorker の publish() を使用して新しい JButton を公開し、リストに追加したいと考えています。しかし、多くの頭痛の種と、System.out.println が何が起こっているのかを把握した後、doBackground() メソッドが終了した後にのみ、process() メソッドの System.out.println() が呼び出されることに気付きました。

ここにコード:

  //run method of the ClientGenerator thread
  public void run()
  {

      System.out.println("Into thread Generator");
      SwingWorker<Void,JButton> worker=new SwingWorker<Void, JButton>()
      {
          int sleepTime;
          @Override
          protected Void doInBackground() throws Exception
          {

              while(checkTime())
              {
                  try
                  {
                      sleepTime=minInterval+r.nextInt(maxInterval - minInterval);
                      System.out.println("Sleeping - "+sleepTime+" milis");
                      Thread.sleep(sleepTime);
                      System.out.println("Woke up,"+sleepTime+" milis elapsed");

                  } catch (InterruptedException e)
                  {
                      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                  }
                  System.out.println("Generating client...");
                  newClient=new Client(clientMinService,clientMaxService,log);
                  System.out.println("Locking lock...");
                  operationsOnTheQueueLock.lock();
                  selectedQueueOperator=selectQueueOperator();
                  System.out.println("Adding new client to queue...");
                  selectedQueueOperator.getQueue().enqueue(newClient);
                  System.out.println("Publishing new JButton...");
                  publish(new JButton("C"+selectedQueueOperator.getClientIndicator()));
                  //}
                  // else
                  //  {
                  //     queueHolder.add(selectedQueueOperator.getQueueClients().get(0);
                  // }

                  System.out.println("Unlocking lock...");
                  operationsOnTheQueueLock.unlock();
                  System.out.println("Lock unlocked! Should enter while again and sleep");

              }
          return null;
          }
          @Override
          public void process(List<JButton> chunks)
          {


                  newClientButton=chunks.get(chunks.size()-1);

                  System.out.println("Process runs.Jbutton index="+newClientButton.getText());
                  newClientButton.setFont(new Font("Arial", Font.PLAIN, 10));
                  newClientButton.setBackground(Color.lightGray);
                  newClientButton.setVisible(true);
                  newClientButton.setEnabled(false);
                  clients=selectedQueueOperator.getQueueClients();
                  clients.add(newClientButton);
                  selectedQueueOperator.setQueueClients(clients);
                  //       if(selectedQueueOperator.getQueueClients().size()>0)
              //   {

                  queueHolder=selectedQueueOperator.getQueueHolder();
                  queueHolder.add(clients.get(clients.size()-1));
                  selectedQueueOperator.setQueueHolder(queueHolder);
          }


           //   return null;  //To change body of implemented methods use File | Settings | File Templates.
      };
      worker.execute();
      try {
          worker.get();
      } catch (InterruptedException e) {
          e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      } catch (ExecutionException e) {
          e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
      }
  }

出力:

Sleeping - 1260 milis
Woke up,1260 milis elapsed
Generating client...
Locking lock...
Adding new client to queue...
Publishing new JButton... ///here I should see "Process runs.Jbutton index=C0"
Unlocking lock...
Lock unlocked! Should enter while again and sleep
Sleeping - 1901 milis
Woke up,1901 milis elapsed
Generating client...
Locking lock...
Adding new client to queue...
Publishing new JButton...///here I should see "Process runs.Jbutton index=C1
Unlocking lock...
Lock unlocked! Should enter while again and sleep
Process runs.Jbutton index=C0  //instead, Process runs only in the end.

これは、2 回の繰り返しの基本的な例です。クライアントは時々生成する必要があるため、最初はスレッドを一定時間スリープさせます。次に、クライアント オブジェクトを生成し、ボタンを生成して JPanel コンポーネントの process() メソッドに追加します。

この最後の部分は、明らかに起こっていません。理由はありますか?SwingWorkerに関して、私は試すことができません...

前もって感謝します!

後で編集:「ロック」は次のように定義されます。

Lock lock = new ReentrantLock();

ClientsGenerator(this) クラスを管理するクラスと、キューからクライアントを削除するクラスからパラメーターとして渡されます。ArrayList& ディスプレイで操作を実行するときに、2 つを同期するために使用されます。

4

2 に答える 2

4

スレッドの要点は、物事が順番に実行されないことです。doInBackground() は、process() が呼び出される前に終了できます (while ループの反復)。doInBackground() は、swing ワーカー スレッドで実行されます。 process() は、EDT で実行されます。

process() は done() の前に実行されます (EDT でも実行されるため)。

他の回答で指摘されているように、テキストのみを公開してから、process() で JButton を作成する必要があります。

通常、EDT から SwingWorker を開始することに注意してください。その場合、EDT で get() を呼び出さないでください (ブロックされます)。

簡単な例:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import javax.swing.*;

public class SwingWorkerTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JPanel panel = new JPanel(new GridLayout(0, 1));
                new SwingWorker<Void, String>() {
                    @Override
                    protected Void doInBackground() throws Exception {
                        Random random = new Random();
                        int count = 1;
                        while (count < 100) {
                            publish("Button " + (count++));
                            Thread.sleep(random.nextInt(1000) + 500);
                        }
                        return null;
                    }

                    @Override
                    protected void process(List<String> chunks) {
                        for (String text : chunks) {
                            panel.add(new JButton(new AbstractAction(text) {
                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    panel.remove((JButton) e.getSource());
                                    panel.revalidate();
                                    panel.repaint();
                                }
                            }));
                        }
                        panel.revalidate();
                        panel.repaint();
                    }
                }.execute();

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(new JScrollPane(panel));
                frame.setPreferredSize(new Dimension(400, 300));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
于 2013-03-28T16:36:16.840 に答える
2

で UI コンポーネントを割り当てたり、アクセスしたりしないでくださいdoInBackground()。すべての UI インタラクションはEvent Dispatch Threadで行う必要があります。これは、done()またはprocess()EDT で実行されます。Swing のシングルスレッドの性質の詳細については、Swing の同時実行を参照してください。

operationsOnTheQueueLockまた、ロックを伴う危険なゲームもあります。スレッドをロックしている可能性があります。関連するすべてのコードを実用的なサンプル、つまりSSCCEとして投稿することを検討してください。

SwingWorkerのドキュメントを参照してください。 publish()/process()メソッドの使用方法のかなり良い例があります。

于 2013-03-28T15:55:58.270 に答える