java SwingWorker 从 doInBackground() 启动可运行对象以及如何通知事件调度线程

发布于 2024-12-17 15:00:17 字数 1098 浏览 2 评论 0原文

刚刚学习了 SwingWorker 并有一个问题
(我正在寻找这个问题的答案,但没有专门解决这个设置)

我正在创建一个小型服务器,最多只有 2-3 个同时连接。
我使用的 Jframe 具有内部类 SwingWorker

在 SwingWorker doInBackground() 我有:

while(true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  Future<Connection> future = es.submit(con , con ); 
  tasks.add(future);
 }

Connection是一个可运行的对象,并在 SwingWorker 中声明为子类。

runnable 完成之前,它会在 SQL 中写入一个条目。
那么这个可运行程序如何在终止之前向 Jframe 事件调度线程发送一个提示。
Jframe 将检查新条目的 SQL 并将其显示给用户。

最好做什么:

1 - 创建一个接口,所有可运行对象都可以向 Jframe 事件调度线程发送消息。

2 - 对所有新连接使用 SwingWorker 插入 runnables 并让 Done() 调用服务器 SwingWorker 中的方法使用 EventQueue.invokeLater.. 调用 Jframe 中的方法

3 - 或使用 PropertyChangeListener (不知何故不确定)

4 - 让每个可运行对象都有 s引用 Jframe 并执行 EventQueue.invokeLater..

just learnd the SwingWorker and have a question
( i have search for a answer to this but non specifically address this setup)

Im creating a small server that will have like max simultaneous 2-3 connections only.
Im using a Jframe that have the inner class SwingWorker

In the SwingWorker doInBackground() i have the:

while(true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  Future<Connection> future = es.submit(con , con ); 
  tasks.add(future);
 }

The Connection is a runnable and declared as a subclass in SwingWorker.

Before the runnable has completed it write an entry in the SQL.
How can then this runnable before it dies send a heads-up to Jframe event dispatch thread.
and the Jframewill check the SQL for the new entry and display it to user.

what is best to do:

1 - create an interface witch all runnable can send messages to Jframe event dispatch thread.

2 - use SwingWorker insted of runnables for all new connections and have Done() call a method in server SwingWorker that call method in Jframe using EventQueue.invokeLater..

3 - or use a PropertyChangeListener (somehow no sure)

4 - Let each runnables have s ref to Jframe and do EventQueue.invokeLater..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

﹏雨一样淡蓝的深情 2024-12-24 15:00:17

SwingWorker 文档非常清楚。您应该子类化 SwingWorker 并在 doInBackground() 方法中执行长任务。您应该在 done() 方法中更新 UI。

确实就是这么简单。

编辑:
为了说得更清楚。假设您的 Connection 类扩展了 SwingWorker,它不需要需要实现 Runnable 并且您也不需要 需要显式提供一个线程池来运行工作线程。只需将 run() 方法的内容放入 doInBackground() 中即可。

现在你的主循环看起来像这样;

while (true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  con.execute();
}

您似乎正在主循环中提交给 ExecutorService 。是否有特定的原因(请注意,SwingWorker 为工作线程管理其自己的内部 ThreadPoolExecutor)。是限制并发客户端数量吗?如果是这样,还有其他方法可以实现这一点。

The SwingWorker docs are pretty clear. You should subclass SwingWorker and perform the long task in the doInBackground() method. You should update the UI in the done() method.

It really is as easy as that.

Edit:
To make it clearer. Assuming your Connection class extends SwingWorker it does not need to implement Runnable and you do not need to explicitly provide a thread pool to run the workers in. Just put the contents of the run() method in doInBackground().

Now your main loop looks something like this;

while (true) {
  Socket client_socket = listen_socket.accept();
  Connection con = new Connection(client_socket, "name");
  con.execute();
}

You seem to be submitting to an ExecutorService in your main loop. Is there a specific reason for this (note that a SwingWorker manages its own internal ThreadPoolExecutor for worker threads). Is it to limit the number of concurrent clients? If so there are other ways to accomplish this.

我们只是彼此的过ke 2024-12-24 15:00:17

我会采取以下措施:在父线程中有一个线程安全的阻塞队列或列表,将传递给工作线程。任务完成后,工作线程会将包含结果条目 ID 的消息发布到此阻塞队列中。父线程将阻塞在队列中等待子线程的结果。每当队列中有一个元素时,父线程就会获取它并从数据库中获取该数据并将其显示给用户。

I would go for the following: have a thread safe blocking queue or list in the parent thread that will be passed to worker threads. Once a task is done, a worker thread will post a message that contains the result entry ID into this blocking queue. The parent thread will block on the queue waiting for results from child threads. Whenever there is an element in the queue, the parent thread will take it and go get that data from DB and display it to user.

风启觞 2024-12-24 15:00:17

我尝试创建一个生成后台工作线程的 SwingWorker 示例,其结果通过固定池 ExecutorService 和 CompletionService 发布。我仍然对在一个线程内创建工作线程,然后在另一个线程(SwingWorker 后台线程)内调用它们的 future 的线程安全性有一些疑问。

例如:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.swing.*;

@SuppressWarnings("serial")
public class TestSwingWorker extends JPanel {
   public static final int POOL_SIZE = 4;
   private JTextArea tArea = new JTextArea(10, 30);
   private JButton doItBtn;

   public TestSwingWorker() {
      doItBtn = new JButton(new AbstractAction("Do It!") {
         public void actionPerformed(ActionEvent ae) {
            swingWorkerRunning(true);
            MySwingWorker mySW = new MySwingWorker();
            mySW.execute();
            tArea.append("SwingWorker started\n");
         }
      });
      JPanel btnPanel = new JPanel();
      btnPanel.add(doItBtn);
      tArea.setEditable(false);
      tArea.setFocusable(false);

      setLayout(new BorderLayout());
      add(new JScrollPane(tArea), BorderLayout.CENTER);
      add(btnPanel, BorderLayout.SOUTH);
   }

   private class MySwingWorker extends SwingWorker<String, String> {
      @Override
      protected String doInBackground() throws Exception {
         ExecutorService execService = Executors.newFixedThreadPool(POOL_SIZE);
         final CompletionService<String> completionService = new ExecutorCompletionService<String>(
               execService);
         new Thread(new Runnable() {

            @Override
            public void run() {
               for (int i = 0; i < POOL_SIZE; i++) {
                  final int index = i;
                  completionService.submit(new Callable<String>() {
                     public String call() throws Exception {
                        Thread.sleep(2000 * index + 500);
                        return "Callable " + index + " complete";
                     }
                  });
                  try {
                     Thread.sleep(1000);
                  } catch (InterruptedException e) {
                  }
               }
            }
         }).start();

         for (int i = 0; i < POOL_SIZE; i++) {
            Future<String> f = completionService.take();
            publish(f.get());
         }

         return "Do in background done";
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            tArea.append(chunk + "\n");
         }
      }

      @Override
      protected void done() {
         try {
            tArea.append(get() + "\n");
         } catch (InterruptedException e) {
            e.printStackTrace();
         } catch (ExecutionException e) {
            e.printStackTrace();
         } finally {
            swingWorkerRunning(false);
         }
      }
   }

   public void swingWorkerRunning(boolean running) {
      doItBtn.setEnabled(!running);
   }

   private static void createAndShowGui() {
      TestSwingWorker mainPanel = new TestSwingWorker();

      JFrame frame = new JFrame("TestSwingWorker");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

欢迎指正!

I tried to create an example of a SwingWorker that generates background worker threads, the results of which get published via a fixed pool ExecutorService and a CompletionService. I still have some questions regarding the thread safety of creating the worker threads inside of one thread, and then calling get on their futures inside of another thread (the SwingWorker background thread).

for example:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.swing.*;

@SuppressWarnings("serial")
public class TestSwingWorker extends JPanel {
   public static final int POOL_SIZE = 4;
   private JTextArea tArea = new JTextArea(10, 30);
   private JButton doItBtn;

   public TestSwingWorker() {
      doItBtn = new JButton(new AbstractAction("Do It!") {
         public void actionPerformed(ActionEvent ae) {
            swingWorkerRunning(true);
            MySwingWorker mySW = new MySwingWorker();
            mySW.execute();
            tArea.append("SwingWorker started\n");
         }
      });
      JPanel btnPanel = new JPanel();
      btnPanel.add(doItBtn);
      tArea.setEditable(false);
      tArea.setFocusable(false);

      setLayout(new BorderLayout());
      add(new JScrollPane(tArea), BorderLayout.CENTER);
      add(btnPanel, BorderLayout.SOUTH);
   }

   private class MySwingWorker extends SwingWorker<String, String> {
      @Override
      protected String doInBackground() throws Exception {
         ExecutorService execService = Executors.newFixedThreadPool(POOL_SIZE);
         final CompletionService<String> completionService = new ExecutorCompletionService<String>(
               execService);
         new Thread(new Runnable() {

            @Override
            public void run() {
               for (int i = 0; i < POOL_SIZE; i++) {
                  final int index = i;
                  completionService.submit(new Callable<String>() {
                     public String call() throws Exception {
                        Thread.sleep(2000 * index + 500);
                        return "Callable " + index + " complete";
                     }
                  });
                  try {
                     Thread.sleep(1000);
                  } catch (InterruptedException e) {
                  }
               }
            }
         }).start();

         for (int i = 0; i < POOL_SIZE; i++) {
            Future<String> f = completionService.take();
            publish(f.get());
         }

         return "Do in background done";
      }

      @Override
      protected void process(List<String> chunks) {
         for (String chunk : chunks) {
            tArea.append(chunk + "\n");
         }
      }

      @Override
      protected void done() {
         try {
            tArea.append(get() + "\n");
         } catch (InterruptedException e) {
            e.printStackTrace();
         } catch (ExecutionException e) {
            e.printStackTrace();
         } finally {
            swingWorkerRunning(false);
         }
      }
   }

   public void swingWorkerRunning(boolean running) {
      doItBtn.setEnabled(!running);
   }

   private static void createAndShowGui() {
      TestSwingWorker mainPanel = new TestSwingWorker();

      JFrame frame = new JFrame("TestSwingWorker");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Corrections most welcome!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文