简体   繁体   中英

How do I stop all child threads from running?

I have a Jersey resource class that basically instantiate a particular thread that intern creates bunch of threads to perform some jobs. The Jersey resource doesn't wait the all the threads to finish their jobs it just returns the result ( particular jobID ) to client immediately after instantiation of thread and keeps the jobID along with thread object in MAP.

Now my requirement is create new resource class with takes jobID as a input which other resource created and stored in Map. This new resource suppose to kill all the thread which is running with that jobID .

I tried to get the thread stored in map using jobID then tried to interrupt that particular thread it didn't actually stopped the all child process.

How do I accomplish this with best possible solution ?

Here are the code snippet for reference

package com.izq.eam.cps.dal2;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;

@Path("Test")
public class TestResource {

    public static Map<Integer, Thread> myThreadMap = new HashMap<>();

    @Path("/startJob")
    @POST
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Integer cspStartMarkingSession(String job_details) {

        Integer jobId = null;

        try {

            if (job_details != null) {
                jobId = createJob(job_details);
            }
        } catch (Exception e) {
            throw new WebApplicationException(e);
        }

        return jobId;
    }

    private Integer createJob(String job_details) {

        Random rand = new Random();
        // Generate random integers in range 0 to 999
        Integer JOBID = rand.nextInt(1000);

        Thread t = new Thread() {
            @Override
            public void run() {

                MyNewThread t = new MyNewThread(job_details);
                t.start();
            }
        };

        t.start();

        myThreadMap.put(JOBID, t);
        return JOBID;
    }

    class MyNewThread extends Thread {
        String job_details;

        public MyNewThread(String job_details2) {
            this.job_details = job_details;
        }

        @Override
        public void run() {

            synchronized (MyNewThread.class) {
                try {
                    System.out.println("JOB DETAILS " + this.job_details);
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    @Path("/stopJob")
    @POST
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public String cspStopMarkingSession(Integer jobID) {

        Thread t = myThreadMap.get(jobID);

        if (t.isAlive()) {
            t.interrupt();   // This is not actually stopping all the child thread instantiated by Thread t ;
        }

        return "JOB Stopping is successfull";

    }

}   

Editing....

I was able to solve this problem some other way ..

Basically, what I was trying out was in my startjob method I had fired linux command which would take certain amount of time to give final output, but it keep pushinh progress of the task to shell-std.out and in case of any error it writes shell-std.err

Below is the code which fires linux command, I have used pool of thread to different task after running command

final Process process = Runtime.getRuntime().exec(command.toString());  // To run linux command

    threadPool.submit(() -> drainToBufferedStream(process.getInputStream(), standardOutput)); // to capture progress of task

      threadPool.submit(() -> drainToBufferedStream(process.getErrorStream(), standardError));  // to capture any error

      threadPool.submit(() -> waitForProcessExit(process)); // final output 

I was passing this threadpool obect back to calling method and store it in MAP with JOBID

Whenever stopJob method called I used get back the threadpool object from MAP and was trying to shutdown thread using threadPool.shutdownnow() method. But however shutdownnow() method was not guaranteed to kill all the threads.

Later I did stored the Process object itself in MAP and tried to destroy process process.destroy() when stopJob called , that killed the process which was executing my command in that way all my threads which was using process object eventually killed.

You child threads are not made interruptible.

Few things to note:

  • only one thread will be able to acquire lock on MyNewThread.class and others will be waiting outside of the synchronized() unable to acquire the lock, let alone call wait()

  • To use Object.wait() to pause the thread, the thread has to own the implicit lock on that object. You have not guaranteed it as your synchronized() obtains the implicit lock of the singleton representing MyNewThread.class while wait() is invoked on this instance

  • Either use synchronized(someSharedObject) followed by someSharedObject.wait() and someSharedObject.notify() (or notifyAll ) which would mean changing how your children threads operate

  • OR use Thread.sleep(timeInMillis) with a while() loop testing for thread's isInterrupted() by the loop. This way you will allow the CPU share occupied by this thread to be available for other threads to use and make your thread to be scheduled back in just to test isInterrupted() again, and if false, invoke sleep() again. This way responsiveness of your child thread to interruptions can be (roughly) regulated by the sleep time.

The code is interuppting the child thread, as you are creating two threads for each job. That is unclear to me what is the purpose of that. Your code is creating two threads, one is getting created in the create-Job method and another is in the run method. You are not putting the thread created in the run method in the map.

Thread t = new Thread() {
            @Override
            public void run() {

                MyNewThread t = new MyNewThread(job_details);
                t.start();
            }
        };
t.start();

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