开发者

How does one stop a thread without a stop() method?

开发者 https://www.devze.com 2023-01-07 16:26 出处:网络
I have question about the Java threads. Here is my scenario: I have a thread calling a method that could take while.The thread keeps itself on that method until I get the result. If I send another re

I have question about the Java threads. Here is my scenario:

I have a thread calling a method that could take while. The thread keeps itself on that method until I get the result. If I send another request t开发者_Python百科o that method in the same way, now there are two threads running (provided the first did not return the result yet). But I want to give the priority to the last thread and don't want to get the results from the previously started threads. So how could I get rid of earlier threads when I do not have a stop method?


The standard design pattern is to use a local variable in the thread that can be set to stop it:

public class MyThread extends Thread {
   private volatile boolean running = true;

   public void stop() {
      running = false;
   }

   public void run() {
      while (running) {
         // do your things
      }    
   }
}

This way you can greacefully terminate the thread, i.e. without throwing an InterruptedException.


The best way really depends on what that method does. If it waits on something, chances are an interrupt will result in an InterruptedException which you handle and cleanly exit. If it's doing something busy, it won't:

class Scratchpad {
    public static void main(String[] a) {
        Thread t = new Thread(new Runnable() {
            public void run() {doWork();}
        });
        t.start();

        try {
            Thread.sleep(50);
        } catch (InterruptedException ie) {}

        t.interrupt();
    }

    private static void doWork() {
        for ( long i = 1; i != 0; i *=5 );
    }
}

In the case above, the only viable solution really is a flag variable to break out of the loop early on a cancel, ala @inflagranti.

Another option for event-driven architectures is the poison-pill: if your method is waiting on a blocking queue for a new item, then you can have a global constant item called the "poison-pill" that when consumed (dequeued) you kill the thread:

try {
   while(true) {
      SomeType next = queue.take();
      if ( next == POISON_PILL ) {
          return;
      }
      consume(next);
   }
} catch //...

EDIT:

It looks like what you really want is an executor service. When you submit a job to an executor service, you get back a Future which you can use to track results and cancel the job.


You can interrupt a Thread, its execution chain will throw an InterruptedException most of the time (see special cases in the documentation).


If you just want to slow down the other thread and not have it exit, you can take some other approach...

For one thing, just like exiting you can have a de-prioritize variable that, when set, puts your thread to sleep for 100ms on each iteration. This would effectively stop it while your other thread searched, then when you re-prioritize it it would go back to full speed.

However, this is a little sloppy. Since you only ever want one thing running but you want to have it remember to process others when the priority one is done, you may want to place your processing into a class with a .process() method that is called repeatedly. When you wish to suspend processing of that request you simply stop calling .process on that object for a while.

In this way you can implement a stack of such objects and your thread would just execute stack.peek().process(); every iteration, so pushing a new, more important task onto the stack would automatically stop any previous task from operating.

This leads to much more flexible scheduling--for instance you could have process() return false if there is nothing for it to do at which point your scheduler might go to the next item on the stack and try its' process() method, giving you some serious multi-tasking ability in a single thread without overtaxing your resources (network, I'm guessing)


There is a setPriority(int) method for Thread. You can set the first thread its priority like this:

Thread t = new Thread(yourRunnable);
t.start();
t.setPriority(Thread.MIN_PRIORITY); // The range goes from 1 to 10, I think

But this won't kill your thread. If you have only two threads using your runnable, then this is a good solution. But if you create threads in a loop and you always sets the priority of the last thread to minimum, you will get a lot of threads.
If this is what is application is going to do, take a look at a ThreadPool. This isn't an existing class in the Java API. You will have create one by yourself.
A ThreadPool is another Thread that manages all your other Threads the way you want. You can set a maximum number of running Threads. And in that ThreadPool, you can implement a system that manages the Thread priority automatically. Eg: You can make that older threads gain more priority, so you can properly end them.

So, if you know how to work with a ThreadPool, it can be very interesting.


According to java.lang.Thread API, you should use interrupt() method and check for isInterrupted() flag while you're doing some time-consuming cancelable operation. This approach allows to deal with different kind of "waiting situations":
1. wait(), join() and sleep() methods will throw InterruptedExcetion after you invoke interrupt() method
2. If thread blocked by java.nio.channels.Selector it will finish selector operation
3. If you're waiting for I/O thread will receive ClosedByInterruptException, but in this case your I/O facility must implement InterruptibleChannel interface.

If it's not possible to interrupt this action in a generic way, you could simply abandon previous thread and get results from a new one. You could do it by means of java.util.concurrent.Future and java.util.concurrent.ExecutorService.

Cosider following code snippet:

public class RequestService<Result> {

private ExecutorService executor = Executors.newFixedThreadPool(3);

private Future<Result> result;

  public Future<Result> doRequest(){
    if(result !=null){
        result.cancel(true);
    }
    result = executor.submit(new Callable<Result>() {
        public Result call() throws Exception {
            // do your long-running service call here
        }
    });
    return result;
  }

}

Future object here represents a results of service call. If you invoke doRequest method one more time, it attempts to cancel previous task and then try to submit new request. As far as thread pool contain more than one thread, you won't have to wait until previous request is cancelled. New request is submitted immediately and method returns you a new result of request.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号