2015-06-24 31 views
0

我已经继承了一个项目,我们使用java并在图像上绘制东西。当用户来回移动滑块来改变图像边缘的阈值时,它会运行一种检测这种情况的方法。这需要200-300ms的时间,所以它将UI锁定了一段时间,但随着用户移动滑块,它不断锁定界面。在java中取消并重用一个(SwingWorker)线程

它们似乎已将其移至后台线程,但每次滑块移动时都会创建一个新线程。所以当用户将滑块移动一英寸时,它会产生80个线程,整个系统会锁定几秒钟。

我不知道如何解决此问题。这是一个回发到UI的回转工作线程。我试着取消(),然后再次执行()该线程,但它似乎不可能。我不想要很多线程时,我可以取消旧的(因为我们不需要旧的预览),所以我认为只有一个会工作。

这是工作者线程。

// 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."); 
     } 
    } 
} 

这是单线程执行程序服务的任务吗?我似乎无法找到关于停止任务的大量信息,但仍继续使用相同的线程(例如我认为的状态模式)。如果可能的话,我不想旋转一堆线程。

+0

我不知道某种生产者 - 消费者可能无法更好地与生产者作为GUI和消费者是运行在后台SwingWorker线程中的另一个长期运行的代码。您的GUI会将映像更改请求排队到消费者可以接受的队列上,进行更改,然后传回GUI。如果有足够的请求堆叠到队列中,则可以跳过其中的大部分请求并仅执行最近的请求。 –

+0

请注意,我的建议有点类似于Swing自己的重绘管理器。 –

+0

后台线程如何在运行长时间运行的任务时检查队列的大小(例如缩放大图或其他东西)? – Mgamerz

回答

1

问题可能是在SwingWorker中完成的工作不可中断,即在doInBackground()中未检查到Thread.interrupted()。所以,即使你取消了工作人员,其实际上并没有停止,但仍然继续产生结果(最终被抛弃)。

可能解决此问题的一种方法是修改代码(最有可能在detectEdges()内部)以及时响应中断。

如果这不是一个可行的选择,改变方法。如果在那里有活跃的工作人员,请跟踪;如果是,请提交新的参数集,否则启动一个。工作者自身需要修改,只有当它产生一个匹配当前参数的结果时才会退出doInBackground()。这种方法可能更容易手动实现,即不使用SwingWorker。