简体   繁体   中英

How to make this search in a new thread

I have search as you type functionality although it searches very fast and I can't notice it even with no multithreading I still want to know how would I use multithreading on this

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

So basically there is a TextField that when its text is changed I go and call a search method in object manager which puts its search result in an array when it finishes.

Then the ListView should update its data to this new array when it finishes.

How can I make the search on one thread and when it finishes it update the list data?!

I believe I can't just call the list function from other thread because GUI stuff should be called from only one thread.

To do this efficiently in a different thread is not as simple as it sounds.

You don't want to create and execute a new thread every time a key is pressed because:

  1. There is system overhead for thread creation which would make that an extremely intensive process
  2. There's no guarantee that the threads will execute and complete in the order they are created, so you may get an earlier thread finishing after a subsequent one and consequentially updating the list with invalid entries.

You could use a single-thread executor service (which keeps one thread alive and uses it to execute Runnables passed into it in order), which would be more efficient, but you'd need to remember to shut it down when your text field is destroyed (if you do ever destroy your text field). Something along these lines:

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

The downside is you are creating a new object every time the value changes, but that isn't nearly as bad as creating a new Thread every time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM