简体   繁体   中英

Java Threads design

I have thread application which process heavy task, i would like to trigger forcibly stop thread upon external flag information. I have tried following design,

public class HeavyTaskThread implements Runnable
{
   private boolean forceStop;

   public void run()
   {
     ..
     ..
     ..
     ..
   }
}

Another fact is i do not have control of logic flow implemented into method run() ; which simply call some third-party program. I was trying with light inner thread class and calling method interrupt() on parent thread, but this does not work.

Please suggest any pattern....

The recommended way to handle the activity of third-party code that you have no control over is to launch it as a different process instead. Then simply kill the process when you need to forcibly stop the code. It's much more clean and safe than killing a thread, since it does not affect the parent process and the OS will take care of the cleanup duty.

If the third party program doesn't respond to an interrupt or setting a condition, an icky option is to try to kill it by nulling a key variable, closing a socket or file, etc. And hoping that it terminates gracefully. Like I said, icky but sometimes you gotta do what you gotta do...

If whatever third-party program you call in run() never returns, you're out of luck. If it returns periodically, you can make it loop, checking against a volatile forceStop boolean and exiting the loop when it's true:

private volatile boolean forceStop;

public void run()
{
    while(!forceStop) {
        ..
        ..
    }
}

While I'd vote for Tudor's answer, in the extreme and if you're desperate:

Option A - Reconstruct problem code.

  • Use your favorite java decompiler & re-create problem class.

  • Add check for Thread.currentThread().isInterrupted() into run .

  • Compile, place your modified class before original library in the classpath.

  • If the original jar was signed you may have to eliminate related signature artifacts.

Option B - Aspect J

  • Examine source for the run method, use your favorite java decompiler if necessary.

  • Identify a some reasonable point in the inner loop for stepping in and stopping.

  • Examine exception handling in code. Any loop-holes?

  • Inject code: throw exceptions, catch exceptions, etc. as needed to back out and return from run .

Here is final analysis...for killing thread.

  1. Using Thread to control the execution of Program B. But then stopping a process means via a thread is not allowed as the related methods are deprecated (stop/suspend etc.,)

  2. Using ThreadGroup ( to have only one thread as its member) and calling 'destroy' on the group. But it again falls on the same track as every thread should be stopped before the destroy operation is attempeted.

  3. Process/ProcessBuilder via Runtime seems to be the better way to obtain a process reference and call destroy(), waitFor() etc. as user @Tudor mentioned.

Here is exact outlined code i have tried and it fails to kill, commented line while(isValid()) represents my another java program invoke.



    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.Callable;
    import java.util.concurrent.CompletionService;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorCompletionService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.TimeUnit;

    class TaskWorker implements Callable {
        private final int number;

        public TaskWorker(int number) {
            this.number = number;
        }

        public Boolean call() throws InterruptedException {
            while (!Thread.currentThread().isInterrupted()) {
                myBusyFunction();
            }
            return true;
        }

        private boolean isValid() {
            return true;
        }

        private void myBusyFunction() {
            //while (isValid()) {
            System.out.println(number + ">....Working.....");
            //}
        }
    }

    public class Test {
        public static void main(final String[] args) {
            CompletionService cs = new ExecutorCompletionService(Executors.newFixedThreadPool(1));
            Collection tasks = new ArrayList(10);
            tasks.add(new TaskWorker(1));
            List> futures = new ArrayList>(tasks.size());
            try {
                for (Callable task : tasks) {
                    futures.add(cs.submit(task));
                }
                //----
                for (int t = 0; t  result = cs.poll(10, TimeUnit.SECONDS);
                    if (result == null) {
                        System.out.println(new Date() + ":Worker Timedout:");
                        //So lets cancel the first futures we find that havent completed
                        for (Future future : futures) {
                            System.out.println("Checking future");
                            if (future.isDone()) {
                                continue;
                            } else {
                                future.cancel(true);
                                System.out.println("Cancelled");
                                break;
                            }
                        }
                        continue;
                    } else {
                        try {
                            if (result.isDone() && !result.isCancelled() && result.get()) {
                                System.out.println(new Date() + ":Worker Completed:");
                            } else if (result.isDone() && !result.isCancelled() && !result.get()) {
                                System.out.println(new Date() + ":Worker Failed");
                            }
                        } catch (ExecutionException ee) {
                            ee.printStackTrace(System.out);
                        }
                    }
                }
            } catch (InterruptedException ie) {
            } finally {
                //Cancel by interrupting any existing tasks currently running in Executor Service
                for (Future f : futures) {
                    f.cancel(true);
                }
            }
            System.out.println(new Date() + ":Done");
        }
    }

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