如何在新线程中进行此搜索

时间:2013-12-20 21:16:47

标签: java multithreading javafx

我键入功能时搜索虽然搜索速度非常快,但即使没有多线程也无法注意到它我仍然想知道如何在此处使用多线程

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应该在完成时将其数据更新为这个新数组。

如何在一个线程上进行搜索,何时完成更新列表数据?!

我相信我不能只从其他线程调用list函数,因为只能从一个线程调用GUI东西。

1 个答案:

答案 0 :(得分:2)

在另一个线程中有效地做到这一点并不像听起来那么简单。

每次按下一个键时都不想创建和执行新线程,因为:

  1. 线程创建存在系统开销,这会使这个过程非常密集
  2. 无法保证线程按照创建顺序执行和完成,因此您可能会在后续线程中完成之前的线程,并因此使用无效条目更新列表。
  3. 您可以使用单线程执行程序服务(使一个线程保持活动状态并使用它来按顺序执行传递给它的Runnables),这样会更有效,但是您需要记住在关闭时将其关闭文本字段被销毁(如果您曾破坏文本字段)。这些方面的东西:

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

    缺点是每次值发生变化时都会创建一个新对象,但这并不像每次创建新线程那么糟糕。