2015-06-24 21 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。