【问题标题】:How to make this search in a new thread如何在新线程中进行此搜索
【发布时间】:2013-12-20 21:16:46
【问题描述】:

我有搜索功能,尽管它搜索速度非常快,即使没有多线程我也无法注意到它我仍然想知道如何在此上使用多线程

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 的东西应该只从一个线程调用。

【问题讨论】:

标签: java multithreading javafx


【解决方案1】:

在不同的线程中高效地执行此操作并不像听起来那么简单。

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

  1. 线程创建会产生系统开销,这会使其成为一个极其密集的过程
  2. 无法保证线程将按照它们创建的顺序执行和完成,因此您可能会得到一个较早的线程完成后续线程并因此使用无效条目更新列表。李>

您可以使用单线程执行器服务(它保持一个线程处于活动状态并使用它来执行按顺序传递给它的 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);
        }
    });

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

【讨论】:

  • 我可以在 searchString 方法中添加一些代码检查以在取消搜索时停止搜索吗??
  • 是的,如果你修改searchString的签名,将Searcher实例作为第二个参数,传入调用该方法的Searcher实例,然后在Searcher类中添加isCancelled()方法searchString 方法可以定期检查调用它的 Searcher 的 isCancelled() 方法。
猜你喜欢
  • 1970-01-01
  • 2020-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-11
相关资源
最近更新 更多