简体   繁体   English

Java:是否有SwingUtilities.invokeNowOrLaterIfEDT(…)或类似的东西?

[英]Java: is there a SwingUtilities.invokeNowOrLaterIfEDT(…) or similar?

(be sure to read the edit below, this question is obviously confusing I'm sorry about that) (请务必阅读下面的修改,此问题显然令人困惑,对此我感到抱歉)

Here's a typical SwingUtilities.invokeLater call: 这是一个典型的SwingUtilities.invokeLater调用:

  SwingUtilities.invokeLater( new Runnable() {
    public void run() {
       ...
    }
  } );

Now I'd like to have what would be a SwingUtilities.invokeNowOrLaterIfEDT . 现在,我想拥有一个SwingUtilities.invokeNowOrLaterIfEDT

Of course I could use my own utility class, like this: 当然,我可以使用自己的实用程序类,如下所示:

public static void invokeNowOrLaterIfEDT( @NotNull Runnable r ) {
    if ( SwingUtilities.isEventDispatchThread() ) {
        Thread t = new Thread( r );
        t.start();
    } else {
        r.run();
    }
}

but this has the drawback of creating a new thread everytime this is called from the EDT (and having to wait for that new thread to be scheduled). 但这有一个缺点,即每次从EDT调用它时都会创建一个新线程(并且必须等待该新线程被调度)。

Another way to do it would be to use one additional thread running during the lifecycle of the app (which could be lazily instantiated) using some blocking queue to enqueue the Runnables . 做到这一点的另一种方法是使用一个附加的线程在应用程序的生命周期中运行(可以延迟实例化),并使用一些阻塞队列来排队Runnables The benefit would be that there wouldn't constantly be threads created everytime I'd call such a method from the EDT. 这样做的好处是,每次我从EDT调用这种方法时,就不会一直创建线程。

Does something like this exist in the default Java APIs? 默认的Java API中是否存在类似的内容?

What would be better: simply creating a new thread each time this is called from the EDT like in the example above or have one additional thread in which Runnables to be executed outside the EDT would be enqueued or something else? 更好的方法是:每次像在上面的示例中一样,每次从EDT调用时都创建一个新线程,或者有一个额外的线程将要在EDT外部执行的Runnables入队或执行其他操作?

EDIT : Just like SwingUtilities.invokeLater may or may not be called from the EDT, the method I had in mind may or may not be called from the EDT. 编辑 :就像SwingUtilities.invokeLater可能会或可能不会从EDT调用一样,我所想到的方法可能会也可能不会从EDT调用。 It is to execute something completely asynchronous that may or may not be triggered from a user action on the GUI / EDT. 这是为了执行完全异步的操作,该操作可能会或可能不会由GUI / EDT上的用户操作触发。 I think SwingUtilities.invokeLater is very convenient to be able to run something in the EDT without having to care when you're invoking it if you're on the EDT or not. 我认为SwingUtilities.invokeLater非常方便,可以在EDT中运行某些内容,而不必关心是否在EDT上调用它。 And I think that the invokeNowOrLaterIfEDT(...) that I showed above is very convenient. 而且我认为上面显示的invokeNowOrLaterIfEDT(...)非常方便。 But I may be mistaken on that. 但是我可能会误会。 Is the need for such a method crazy? 对这种方法的需求疯狂吗? Now I'm starting to doubt!? 现在我开始怀疑!?

EDIT TWO : I haven't been clear at all and I realize it, sorry about that. 编辑二 :我还不清楚,我意识到这一点,对此感到抱歉。 The things I want to run asynchronously not from the EDT are not super long process and there's no need to have any update like progress bar or anything showing what's going on. 我想不通过EDT异步运行的东西并不是一个漫长的过程,也不需要进行任何更新,例如进度条或任何显示正在发生的事情。 It's also not a problem if it's single-threaded/queued (obviously, I stated it in the question). 如果它是单线程/排队的,这也不是问题(显然,我在问题中已经指出)。 I'm not at all after a thread pool to efficiently spread the load on various cores etc. It's just that these are small computation that do not need to be run on the EDT and that may be called from the EDT or not. 我根本不打算在线程池中高效地将负载分散到各个内核等上。只是这些都是很小的计算,不需要在EDT上运行,而可以从EDT调用也可以不调用它。 It's really just tiny asynchronous stuff I want to execute outside the EDT. 我实际上只是想在EDT外部执行的微小异步内容。 It's not an issue if they're all queued on the same thread etc. 如果它们都在同一个线程中排队等等,这不是问题。

But now, thanks to your answers, I also realize that if such a thing was implemented using a single thread and a Runnable queue, then it would be very easy to shot oneself in the foot by calling such a utility method for long computation that would then all be queued instead of correctly multi-threaded. 但是现在,感谢您的回答,我还意识到,如果使用单线程和Runnable队列来实现这样的事情,那么通过调用这种实用程序方法进行长时间计算将很容易使自己陷入困境然后将所有队列排队,而不是正确的多线程。

  1. Are you sure this is what you really want to do, because in any case in your method a runnable will never be run on EDT. 您确定这是您真正想要做的吗,因为无论如何在您的方法中,可运行对象都不会在EDT上运行。
  2. Now for your anwser, depening on how often and from how many threads this method could be called, I think you should use a ThreadPool. 现在,对于您的助手,取决于可以调用此方法的频率和线程数,我认为您应该使用ThreadPool。 I would suggest using ThreadPoolExecutor and other APIs in the concurrent package. 我建议在并发包中使用ThreadPoolExecutor和其他API。

One advantage of using the java.util.concurrent API like ThreadPoolExecutor and Executors is that you can fine tune a lot of parameters and the entire pooling system by simply calling direct API's and no extra effort. 使用诸如ThreadPoolExecutor和Executors之类的java.util.concurrent API的优点之一是,您可以通过直接调用直接API来微调很多参数和整个池系统,而无需付出额外的努力。

Another option (in addition to Suraj's ) is to use a SwingWorker . 除了Suraj之外,另一个选择是使用SwingWorker

This class is specifically designed for what you want to do: take a (possibly long running) process from the EDT and execute it in a separate thread. 该类是专门为您要执行的操作而设计的:从EDT中获取一个(可能长时间运行的)进程,并在一个单独的线程中执行它。 The SwingWorker has the advantage of handling all the thread context switches, and also allows you to provide updates back to the EDT (for example, to display a progress bar), without having to worry about the threading yourself. SwingWorker的优点是可以处理所有线程上下文切换,并且还允许您将更新提供回EDT(例如,显示进度条),而不必担心自己的线程。

It seems like your question boils down to "is it better to create a new thread for every asynchronous call, or use a dedicated thread/thread pool"? 看来您的问题归结为“为每个异步调用创建一个新线程还是使用专用线程/线程池更好”?

Unfortunately, I think the answer is "it depends". 不幸的是,我认为答案是“取决于”。 If you know these tasks are short and rare, a new thread is probably fine. 如果您知道这些任务很短且很少见,那么使用新线程可能就可以了。 If you're worried about long computations blocking each other, you probably want a thread pool. 如果您担心长时间的计算会相互阻塞,则可能需要线程池。

static ExecutorService ex = Executors.newCachedThreadPool();

public static void invokeOutsideEDT(Runnable r) {
    if (SwingUtilities.isEventDispatchThread()) {
       ex.submit(r);
    } else {
        r.run();
    }
}

As Suraj noted , the concurrent package gives you a lot of off-the-shelf choices here. 正如Suraj所指出的concurrent 发包在这里为您提供了许多现成的选择。 Executors.newCachedThreadPool() I've used above will add threads as needed, reusing old threads; 我上面使用的Executors.newCachedThreadPool()将根据需要添加线程,重用旧线程; but you could try Executors.newSingleThreadExecutor() instead and see if the long-running tasks are really a problem, or use Executors.newFixedThreadPool() with a set number of threads to make sure you can always handle n concurrent tasks even if some of them are long-running. 但是您可以改用Executors.newSingleThreadExecutor()来查看长时间运行的任务是否确实存在问题,或者将Executors.newFixedThreadPool()与一定数量的线程一起使用,以确保即使某些情况下,您始终可以处理n并发任务他们是长期的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM