简体   繁体   English

在Java中取消并重用(SwingWorker)线程

[英]Cancel and reuse a (SwingWorker) thread in java

I've inherited a project where we are using java and drawing stuff over an image. 我继承了一个项目,我们在其中使用Java并在图像上绘制内容。 As a user moves a slider back and forth to change the threshhold of edges on the image and it runs a method that detects this. 当用户来回移动滑块以更改图像边缘的阈值时,它会运行一种检测该阈值的方法。 This takes like 200-300ms so it locks up the UI for a bit but as the user moves the slider it constantly keeps locking up the interface. 这大约需要200-300毫秒,因此它会锁定UI一段时间,但是随着用户移动滑块,它会不断锁定界面。

They appear to have moved this to a background thread but it creates a new one every time the slider moves. 他们似乎已将其移至后台线程,但每次滑块移动时都会创建一个新线程。 So as the user moves the slider maybe an inch it spawns like 80 threads and the whole system locks up for a couple of seconds. 因此,当用户将滑块移动一英寸时,它会产生80条线程,并且整个系统会锁定几秒钟。

I'm not sure how to work around this issue. 我不确定如何解决此问题。 It's a swingworker thread that posts back to the UI. 这是一个swingworker线程,它回发到UI。 I tried canceling() and then execute()ing the thread again but it appears that's not possible. 我试着取消(),然后再次执行()线程,但这似乎是不可能的。 I don't want lots of threads when I can just cancel the old one (since we don't need the old preview) so I think only one would work. 当我只需要取消旧的线程时就不需要很多线程(因为我们不需要旧的预览),所以我认为只有一个线程可以工作。

Here is the worker thread. 这是工作线程。

// WORKER
private class ThresholdWorker extends SwingWorker<BufferedImage, Object> {
    // long-running code to be run in a worker thread
    @Override
    public BufferedImage doInBackground() throws Exception {
        @SuppressWarnings("static-access")
        BufferedImage img = new BufferedImage(imagePanel.rect_width, imagePanel.rect_height, BufferedImage.TYPE_3BYTE_BGR);
        img = imagePanel.detectEdges();
        return img;
    } // end method doInBackground

    // code to run on the event dispatch thread when doInBackground returns
    @Override
    protected void done() {
        try {
            @SuppressWarnings("static-access")
            BufferedImage Img = new BufferedImage(imagePanel.rect_width, imagePanel.rect_height, BufferedImage.TYPE_3BYTE_BGR);
            Img = get();
            imagePanel.standardRectEdgesDilated = Img;
            imagePanel.repaint();
        } catch (InterruptedException ignore) {
        } catch (ExecutionException ex) {
            IdentiFrog.LOGGER.writeException(ex);
            System.err.println("Error encountered while performing calculation.");
        }
    }
}

Is this a task for a single thread executor service? 这是单线程执行器服务的任务吗? I can't seem to find a lot of info on stopping a task but continuing to use the same thread (eg a state pattern I think). 我似乎找不到很多有关停止任务但继续使用同一线程的信息(例如,我认为是状态模式)。 I don't want to spin up a bunch of threads if possible. 如果可能的话,我不想增加一些线程。

The problem is probably that the work done in the SwingWorker is not interruptible, that is in doInBackground() Thread.interrupted() is not checked. 问题可能是在SwingWorker中完成的工作是不可中断的,即在doInBackground()中未检查Thread.interrupted()。 So even if you cancel the worker, its not actually stopping but still continues to produce a result (that is ultimately thrown away). 因此,即使您取消了该工作程序,它实际上并没有停止但仍会继续产生结果(最终被丢弃)。

One way to possibly solve this is to modify the code (most likely the inside of detectEdges()) to timely respond to interruption. 解决此问题的一种方法是修改代码(最有可能在detectEdges()内部)以及时响应中断。

If thats not a feasible option, change the approach. 如果那不是可行的选择,请更改方法。 Keep track if there is an active worker out there; 跟踪是否有在职工人; if yes, submit the new parameter set to it, otherwise start one. 如果是,则向其提交新的参数集,否则开始一个。 The worker itself then needs modification to only exit doInBackground() once it has produces a result that matches the current parameters. 然后,工作程序本身需要进行修改以仅在产生与当前参数匹配的结果后才退出doInBackground()。 This approach may be easier to implement by hand, that is, not using SwingWorker. 手动实现此方法可能更容易,也就是说,不使用SwingWorker。

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

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