关于Java线程超时退出的问题.

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java线程超时退出的问题.相关的知识,希望对你有一定的参考价值。

小弟近来有个任务是这样的,JAVA主程序中开启一个线程,我希望在一定的时间范围内 如果这个线程还没有运行完,就采取一些方法主动将他干掉,试了网上很多的方法都没有用,顶多是能抛出个异常,通知一下超时,但是线程还是在继续运行。
请教各位大虾们该怎么解决啊!!!
就没有哪个神人,能解决这个问题么. 我开的这个线程可能是要和别的程序进行交互,交互过程中可能会卡死,所以我才想能不能采取一些方法将他主动停掉,你们介绍的方法都不行...

结贴了吧.

参考技术A 你在捕捉到的异常中,调用一下线程的interrupt()方法就可以对线程进行中断,当然,你的线程中的run方法中不能catch了interrupt()异常并且忽视这个异常。

比如在出现异常的地方:
threadA.interrupt();

而threadA的run方法中:
public void run()
while(true)
try
....
catch (InterruptedException)
break; //这样是可以的,如果没有break或者修改为continue则不行




也可以将这个放在while循环之外。
public void run()
try
while(true)

....

catch (InterruptedException)
....

本回答被提问者采纳
参考技术B class AutoCloseThread implements Runnable
private int limit;//限制
private Timer timer=new Timer();

@Override
public void run()
TimerTask task=new TimerTask()
@Override
public void run()
limit++;
if(limit>50) timer.cancel();

;
timer.schedule(task, 0, 1000);
timer.schedule(task, 0);



shaoyunlu 2010-7-13 17:31:19
timer.schedule(task, 0, 1000);
timer.schedule(task, 0);
这两个 要一起写?
军 2010-7-13 17:44:31
不是
军 2010-7-13 17:44:43
timer.schedule(task, 0, 1000);
timer.schedule(“webservice”, 0);

参考资料:还有其他问题的话,给我发百度消息

参考技术C java.util.concurrent.Future
默认实现java.util.concurrent.FutureTask
你去查一下有关这个类的用法吧,他能满足你的要求。
或者java.util.concurrent.ExecutorService这个线程池也行。
参考技术D 线程中run()写法类似下面
public void run()

....
while(t<毫秒)

。。。。。
}//程序结束


在while里设置线程停止条件,我这个是判断时间。也可以设置一个标识,例如:
public void run()

boolean isEnd = false;
.....
while(isEnd == false)

if(....)

isEnd = true;
break;

......



有空看看《JAVA多线程设计》,好书,结合设计模式讲的JAVA多线程。浅显易懂

===============补充你的补充问题==============

你既然说是想主动停掉。这个意思已经很明显了,你现在的问题只是,你在代码设计思路上陷入死循环了。
所谓主动停掉就是到了指定的条件,程序自然死亡结束。你要做的就是写一个销毁方法,将线程结束的所有操作都写在里面,包括你调用或交互的其它程序结束方法。然后在指定条件下调用这个销毁操作。我不知道我说的明白不?

[Java]_[初级]_[如何调用外部命令获取输出并设置它的超时退出]

场景

  1. 在开发Java程序的时候,有时候需要执行外部命令以获取特定信息,但是外部命令执行可能由于某些原因(比如CPU,内存占用高后延迟执行)比正常执行的时间要长,有时候甚至挂起阻塞了Java线程的执行。那么我们如何使用标准库来完成调用外部命令的超时时间设置?

  2. 还有基本的问题,如何读取启动进程的输出?

说明

  1. Java使用ProcessBuilder来创建外部命令的进程,并使用方法command来异步执行外部命令.
ProcessBuilder ps = new ProcessBuilder();
ps.command(命令路径);
Process process = ps.start();
  1. 之后通过对象processprocess.getInputStream()获取一个连接到进程输出的输入流,这个输入流使用管道的方式连接到进程的标准输出上,所以读取这个输入流就可以读取这个进程的输出。通过读取这个进程的输出并存储到StringBuffer里.
StringBuffer line = new StringBuffer();
String temp = "";
try(BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))){
    while ((temp = in.readLine()) != null)
        line.append(temp);

    exitCode = process.waitFor();
}catch (Exception e){
    e.printStackTrace();
}finally {
    if(exitCode != 0)
        process.destroy();
}
  1. 为了外部进程的超时判断,那么外部进程肯定需要额外的线程进行运行和读取输出,使用了线程池ThreadPoolExecutor来执行任务会比较好, 避免频繁的创建线程。而Executor.submit返回了一个Future对象,这个对象是并发包里的类,主要是可以异步获取工作线程返回的值。通过这个Future对象可以获取到外部进程执行的结果,它还有设置延时等待的get方法正好合适。
String java.util.concurrent.Future.get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
  1. 在使用Futureget获取返回结果时,可以通过抛出的超时异常来销毁未结束的进程。关于Future的介绍可以参考课程JDK8-Java8-JavaSE8新特性和增强功能.
TaskCallable callable = new TaskCallable();
Future<String> handler = executor.submit(callable);
String message = "";
try {
    message = handler.get(kGenWaitTimeoutSeconds, TimeUnit.SECONDS);
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
} catch (TimeoutException e) {
    callable.cancelProcess();
}
  1. 在以下的例子里我把调用外部命令封装到一个Callable<String>对象里,方便Executor.submit调用.

例子

package com;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Test;

public class ProcessExecTest {

    private ThreadPoolExecutor executor;
    private BlockingQueue<Runnable>queue;

    private static int queueSize = 1024;
    private static int threadKeepAliveTime = 120;
    private static int kGenWaitTimeoutSeconds = 10;
    
    public static void print(String key,String str){
        System.out.println(key+": "+str);
    }

    public ProcessExecTest(){
        int processors = Runtime.getRuntime().availableProcessors();

        // 常规任务
        queue = new LinkedBlockingQueue<Runnable>(queueSize);
        executor = new ThreadPoolExecutor(processors,processors,
                threadKeepAliveTime,TimeUnit.SECONDS, queue);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
    }

    @Test
    public void testProcess(){
        TaskCallable callable = new TaskCallable();
        Future<String> handler = executor.submit(callable);
        String message = "";
        try {
            message = handler.get(kGenWaitTimeoutSeconds, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            callable.cancelProcess();
        }
        
        print("message",message);
    }

    public static class TaskCallable implements Callable<String>{

        private Process process;
        private int exitCode = 1;

        public void cancelProcess(){
            if(process != null && exitCode != 0)
                process.destroy();
        }

        public TaskCallable(){
        }

        @Override
        public String call() throws Exception {

            File dir = new File("C:\\\\Windows\\\\System32");
            ProcessBuilder ps = new ProcessBuilder();
            ps.directory(dir);
            Path dirPath = dir.toPath();
            Path exePath = dirPath.resolve("cmd.exe");

            ps.command(exePath.toString(),"/C","echo tobey");
            process = ps.start();
            if(process == null)
                return "";

            StringBuffer line = new StringBuffer();
            String temp = "";
            try(BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))){
                while ((temp = in.readLine()) != null)
                    line.append(temp);

                exitCode = process.waitFor();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(exitCode != 0)
                    process.destroy();
            }
            return  (exitCode == 0)?line.toString():"";
        }
    }
}

输出

message: tobey

参考

  1. java - ExecutorService that interrupts tasks after a timeout - Stack Overflow

以上是关于关于Java线程超时退出的问题.的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA的关闭serverSOCKET

关于java.sql.SQLRecoverableException: Closed Connection异常的解决方案(转)

java连接redis超时问题怎么解决

[Java]_[初级]_[如何调用外部命令获取输出并设置它的超时退出]

[Java]_[初级]_[如何调用外部命令获取输出并设置它的超时退出]

JAVA线程虚假唤醒