有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

SwingJava:是否存在SwingGutilities。invokeNowOrLaterIfEDT(…)还是类似的?

(请务必阅读下面的编辑,这个问题显然令人困惑,对此我很抱歉)

下面是一个典型的SwingUtilities.invokeLater调用:

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

现在我想要一个SwingUtilities.invokeNowOrLaterIfEDT

当然,我可以使用自己的实用程序类,如下所示:

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

但这有一个缺点,即每次从EDT调用时都会创建一个新线程(并且必须等待新线程被调度)

另一种方法是在应用程序的生命周期(可以延迟实例化)中使用一个额外的线程,使用一些阻塞队列将Runnables排队。这样做的好处是,每次我从EDT调用这样的方法时,不会不断地创建线程

默认Java API中是否存在类似的内容

更好的方法是:每次从EDT调用它时,只需创建一个新线程,就像上面的例子一样,或者有一个额外的线程,其中要在EDT之外执行的Runnables将被排队,或者其他什么

EDIT:就像SwingUtilities.invokeLater可能从EDT调用,也可能不从EDT调用一样,我想到的方法可能从EDT调用,也可能不从EDT调用。它是执行完全异步的东西,可能会也可能不会从GUI/EDT上的用户操作触发。我认为SwingUtilities.invokeLater能够在EDT中运行某些东西非常方便,而不必关心调用它时是否在EDT上。我认为我上面展示的invokeNowOrLaterIfEDT(...)非常方便。但我可能弄错了。需要这样一种方法是疯狂的吗?现在我开始怀疑了

编辑两个:我一点也不清楚,我意识到了这一点,很抱歉。我不想从EDT异步运行的东西不是超长的进程,也不需要任何更新,比如进度条或任何显示正在发生的事情。如果它是单线程/排队的,这也不是问题(显然,我在问题中已经说过)。我根本不想要一个线程池来有效地将负载分散到各种内核上,只是这些都是小计算,不需要在EDT上运行,可以从EDT调用,也可以不从EDT调用。这只是我想在EDT之外执行的微小的异步操作。如果它们都在同一个线程上排队,这不是问题

但是现在,多亏了你的回答,我也意识到,如果这样的事情是用一个线程和一个可运行的队列来实现的,那么调用这样一个实用方法进行长时间的计算会非常容易,然后所有的计算都会排队,而不是正确的多线程


共 (3) 个答案

  1. # 1 楼答案

    您的问题似乎可以归结为“是为每个异步调用创建一个新线程更好,还是使用一个专用的线程/线程池更好”

    不幸的是,我认为答案是“视情况而定”。如果你知道这些任务很短很少见,那么一个新的线程可能就可以了。如果你担心长时间的计算会互相阻塞,你可能需要一个线程池

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

    As Suraj notedconcurrent软件包为您提供了很多现成的选择Executors.newCachedThreadPool()我在上面使用的方法将根据需要添加线程,重用旧线程;但是你可以试试Executors.newSingleThreadExecutor(),看看长时间运行的任务是否真的是个问题,或者使用Executors.newFixedThreadPool()和一定数量的线程来确保你总是可以处理n并发任务,即使其中一些是长时间运行的

  2. # 2 楼答案

    另一个选项(除了Suraj's)是使用^{}

    这个类是专门为您想要做的事情而设计的:从EDT中获取一个(可能是长时间运行的)进程,并在一个单独的线程中执行它。SwingWorker具有处理所有线程上下文切换的优势,还允许您提供回EDT的更新(例如,显示进度条),而无需担心线程本身

  3. # 3 楼答案

    1. 你确定这是你真正想要做的,因为在你的方法中,无论如何runnable都不会在EDT上运行
    2. 现在,对于anwser,取决于调用这个方法的频率和线程数,我认为应该使用线程池。我建议在并发包中使用ThreadPoolExecutor和其他API

    使用java的一个优点是。util。像ThreadPoolExecutor和Executors这样的并发API就是,只需调用直接API,无需额外努力,就可以微调许多参数和整个池系统