2

I have page with filter form, a few buttons and big grid. I can search data, based on filter form, and show data in grid. Searching data provides thread, it may take about secs to mins. When I want to click button to stop searching (basically to stop thread), the action is performed always after the thread is done. But I need to perform click event while thread is working. Does somebody know how to do it? :)

UI has @Push(PushMode.MANUAL), and pushing is working fine

Simplified code:

@SpringComponent
@UIScope
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DistraintSearchComponent extends CustomComponent {

    @Autowired
    private Service service
    private Button searchButton = new Button("Search");
    private Button stopButton = new Button("Stop");
    private Thread searchThread;

    public void init(){

        searchButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                searchThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        List<Results> results = service.findByFilter(filter); //this can take some time
                        refreshGrid(results);
                        getUI().push();
                    }
                });
                searchThread.start();
            }
        });

        stopButton.addClickListener(new ClickListener() {

            @Override
            public void buttonClick(ClickEvent event) {
                searchThread.interrupt();
            }
        });

    }
}

Thank you

NoPa147
  • 49
  • 3
  • 2
    You will have to add your searching/thread code. We do not know how are you checking when search should stop and what could be wrong with it. How do you know when search ended (on client)? Are you using polling/push, [properly accessing UI from another thread](https://vaadin.com/docs/v7/framework/advanced/advanced-push.html)? – Piro Aug 14 '18 at 11:51
  • @Piro I added some simplified code – NoPa147 Aug 14 '18 at 12:12
  • Are you swallowing InterruptedException? – Tatu Lund Aug 14 '18 at 13:06
  • @TatuLund I got no exception – NoPa147 Aug 14 '18 at 13:29
  • Thats strange, anyway my point was that you should not swallow it, but rethrow. Otherwise e.g. if you have some big transaction in findByFilter(..), it will not get interrupted. – Tatu Lund Aug 14 '18 at 16:47
  • I can only guess what your service is doing, but I recommend to check this: https://stackoverflow.com/questions/38880069/spring-cancel-async-task – Tatu Lund Aug 14 '18 at 17:31
  • @TatuLund I do not know either what this service does actually, it is third party service, I ask for data and wait until I get them – NoPa147 Aug 15 '18 at 07:33
  • I see. It is probably not interrupt aware, see also answer by Piro. Since you are using Spring, you should possibly use its @Async to do the Thread instead, more info is here: https://dzone.com/articles/spring-and-threads-async – Tatu Lund Aug 15 '18 at 07:45

1 Answers1

2

searchThread.interrupt() does not stop the thread without thread cooperating. From documentation we can see what it does:

If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

Reason is you cannot stop execution everywhere, that would be a lot of undefined behavior. Instead you should stop your thread in controlled way.

So in your search thread (in your case it would be probably inside service.findByFilter(filter);) you should be repeatedly checking if thread should end:

 while (!Thread.currentThread().isInterrupted()) {
 // fetch another entry
}

Documentation also says that you can receive InterruptedException and ClosedByInterruptException so you can stop processing when handling this exceptions. ClosedByInterruptException is IOException so both exceptions are checked exceptions that have to be handled anyway, but maybe you do not invoke anything that would throw such exception.

try {
    Thread.currentThread().sleep(123);
} catch (InterruptedException e) {
    return; // return from service.findByFilter(filter);
}
Community
  • 1
  • 1
Piro
  • 1,367
  • 2
  • 19
  • 40