如何停止所有子线程运行?

时间:2018-07-19 08:42:49

标签: java multithreading jersey threadpool

我有一个Jersey资源类,该类基本上实例化了一个特定的线程,该线程由intern创建一堆线程来执行一些工作。 Jersey资源不会等待所有线程完成其工作,它只是在线程实例化后立即将结果(特别是jobID)返回给客户端,并将jobID与线程对象一起保留在MAP中。

现在,我的要求是使用jobID作为输入来创建新的资源类,其他资源已创建并存储在Map中。这个新资源假定杀死所有与该jobID运行的线程。

我尝试使用jobID将线程存储在map中,然后尝试中断该特定线程,但实际上并未停止所有子进程。

如何用最佳解决方案来做到这一点?

以下是供参考的代码段

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";

    }

}   

编辑。...

我能够通过其他方式解决此问题。

基本上,我要尝试的是在我的startjob方法中,我已经启动了linux命令,这将花费一定的时间来提供最终输出,但是它将任务的进度推进到shell-std.out,并且在它会写入shell-std.err

的任何错误

下面是触发linux命令的代码,运行命令后,我已将线程池用于不同的任务

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 

我将这个线程池对象传递回调用方法,并使用JOBID将其存储在MAP中

每当我使用stopJob方法时,我都会从MAP中获取线程池对象,并尝试使用threadPool.shutdownnow()方法关闭线程。但是,不能保证使用shutdownnow()方法杀死所有线程。

后来,我确实将Process对象本身存储在MAP中,并在stopJob调用时试图销毁process.destroy(),这杀死了正在执行命令的进程,这样我使用进程对象的所有线程最终都被杀死了。

2 个答案:

答案 0 :(得分:0)

您的子线程不会被打断。

几件事要注意:

  • 只有一个线程能够获得对MyNewThread.class的锁定 而其他人将在synchronized()无法 获取锁,更不用说wait()

  • 要使用Object.wait()暂停线程,线程必须拥有该对象上的隐式锁。您不能保证它是您的 synchronized()获得单例的隐式锁定 在MyNewThread.class实例上调用wait()时代表this

  • 使用synchronized(someSharedObject),然后使用someSharedObject.wait()someSharedObject.notify()(或notifyAll),这将意味着更改子线程的操作方式

  • OR Thread.sleep(timeInMillis)while()进行循环测试,以对线程的isInterrupted()进行循环测试。这样,您将允许该线程占用的CPU份额可供其他线程使用,并使您的线程被调度回去以再次测试isInterrupted();如果为false,则再次调用sleep() 。通过这种方式,您的子线程对中断的响应能力可以(大致)由睡眠时间来调节。

答案 1 :(得分:0)

该代码正在插入子线程,因为您要为每个作业创建两个线程。我不清楚这样做的目的是什么。您的代码正在创建两个线程,一个在create-Job方法中创建,另一个在run方法中创建。您没有将在run方法中创建的线程放入映射中。

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

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