2013-12-20 34 views
1

,你雖然它搜索速度非常快,我甚至不能沒有多線程我還是想知道我將如何使用多線程對這個如何使一個新線程搜索

注意到這類型的功能,我已經搜索
search.textProperty().addListener(new ChangeListener<String>() { 
      @Override 
      public void changed(ObservableValue<? extends String> observableValue, String s, String s2) { 
       manager.searchString(s2); 
       listView.getItems().setAll(manager.getList()); 
      } 
     }); 

所以基本上有一個TextField,當它的文本被改變時,我去調用對象manager中的搜索方法,當搜索結果完成後,它將其搜索結果放入數組中。

然後當ListView完成時,它應該將其數據更新到這個新數組。

如何在一個線程上進行搜索,何時完成更新列表數據?

我相信我不能從其他線程調用列表函數,因爲GUI的東西應該只從一個線程調用。

+0

對於Swing,有一個關於併發性的好文檔(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。對於JavaFX,似乎有一個[類似文檔](http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm),雖然沒有讀過它... – dst

回答

2

要在不同線程中有效地做到這一點並不像聽起來那麼簡單。

你不想創建並執行新的線程每一個鍵被按下的時間,因爲:

  1. 有系統開銷創建線程這將使這一個非常密集的過程
  2. 有沒有保證線程將按照它們的創建順序執行並完成,因此您可能會在之後的某個後續線程中獲得的較早線程,並隨後使用無效條目更新列表。

你可以使用一個線程執行服務(而保持一個線程活着,並用它來執行的Runnable傳遞給它按順序),這將是更有效的,但你要記住關閉它當你的文本字段被破壞時(如果你破壞了你的文本字段)。沿着這些路線的東西:

// first of all, at the class level (assuming listView and manager are both class-level variables, preferably final ones, too): 

// An INNER class implementing Runnable which will carry out the searching 
private class Searcher implements Runnable { 
    private volatile boolean cancelled = false; 
    private final String searchTerm; 
    Searcher(String searchTerm) { 
     this.searchTerm = searchTerm; 
    } 

    public void cancel() { 
     cancelled = true; 
    } 

    @Override 
    public void run() { 
     // remember that there's no guarantee that this will execute before the NEXT keypress, so we add a check to ensure that we still want to perform the search when it gets executed: 
     if (!cancelled) { 
      manager.searchString(searchTerm); 
      Platform.runLater(listViewUpdater); // listViewUpdater is defined below 
     } 
    } 
} 

// a Runnable to actually update the GUI after a seach has been performed 
private Runnable listViewUpdater = new Runnable(){ 
    @Override 
    public void run() { 
     listView.getItems().setAll(manager.getList()); 
    } 
} 

private ExecutorService executor = Executors.newSingleThreadExecutor(); 
private Searcher lastSearcher = null; 

// ... then, in the method which sets up the GUI 
search.textProperty().addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(ObservableValue<? extends String> observableValue, String s, String s2) { 
      if (lastSearcher != null) { 
       lastSearcher.cancel(); // prevents lastSearcher from running if it hasn't done so already 
      } 
      lastSearcher = new Searcher(s2); 
      executor.submit(lastSearcher); 
     } 
    }); 

的缺點是要創建每次值變化的新對象,但事實並非幾乎每次都創建一個新線程的那樣糟糕。

+0

我可以添加一些在searchString方法中檢查代碼以在取消時停止搜索? –

+1

是的,如果您更改searchString的簽名以將Searcher實例作爲第二個參數,請傳入調用方法的Searcher實例,並在Searcher類中添加isCancelled()方法,然後searchString方法可以定期檢查搜索者的isCancelled()方法調用它。 – megaflop

相關問題