监听多线程超时:Future

众所周知多线程是个好东西,合理地使用多线程可以提高资源利用率,缩短大批量任务的处理时间。当然高效的同时问题也是少不了的。本文将介绍一些针对线程超时的处理方法,希望对初学者能有所帮助 ^_^


场景

1. 线程意外地在某个while或者哪里陷入死循环了(如果不是意外地请一定先修正逻辑错误)

2. 线程执行了某个耗时巨大的任务,而我希望不管执没执行完,都要在限定时间内结束线程


解决方法

java.util.concurrent.Future

来看下文档里对此接口的介绍


翻译下这段话:

第一句异步计算的结果,听起来像是这样(当然在语法上下面这句是不对的)

Future task = new MyThread().run();

拿到这个result后,我们可以用get()获取线程的执行结果

String result = task.get();

可以用get(time, unit)来获取线程的执行结果,同时监听超时

String result = task.get(1000, TimeUnit.MILLISECONDS);

可以用cancel()来取消任务

task.cancel();

以及其他一些方法

boolean isDone = task.isDone();
boolean isCancelled = task.isCancelled();


开始写代码吧。


监听单线程超时

public class TestThread implements Callable<String> {

	@Override
	public String call() {
		System.out.println(System.currentTimeMillis() + "进来了" + this.hashCode());
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {}
		
		return System.currentTimeMillis() + "出来了" + this.hashCode();
	}
	
	public static void main(String[] args) {
		FutureTask<String> task = new FutureTask<String>(new TestThread());
		new Thread(task).start();
		
		try {
			//3000就是超时时间
			String result = task.get(3000, TimeUnit.MILLISECONDS);
			System.out.println(result);
		} catch (InterruptedException e) {
			System.out.println("线程已经停止了");
		} catch (ExecutionException e) {
		} catch (TimeoutException e) {
			System.out.println(System.currentTimeMillis() + "线程超时了,打死他");
			task.cancel(true);
		}
	}
}

来看看控制台的输出

1524559858691进来了1893883033
1524559861691线程超时了,打死他

是的,很简单就实现了。但其实这里有个大坑,相信你注意到了我在上方写的标题:监听单线程超时-_- 因为get方法是阻塞的。

如果你这样写

FutureTask<String> task = new FutureTask<String>(new TestThread());
FutureTask<String> task2 = new FutureTask<String>(new TestThread());
new Thread(task).start();
new Thread(task2).start();
		
try {
	String result = task.get(3000, TimeUnit.MILLISECONDS);
	System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
} catch (TimeoutException e) {
	System.out.println(System.currentTimeMillis() + "线程超时了,打死他");
	task.cancel(true);
}
		
try {
	String result = task2.get(3000, TimeUnit.MILLISECONDS);
	System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
} catch (TimeoutException e) {
	System.out.println(System.currentTimeMillis() + "线程超时了,打死他");
	task.cancel(true);
}

看下结果,线程1被打死了,线程2逍遥法外

1524559903444进来了1584403035
1524559903444进来了1893883033
1524559906444线程超时了,打死他
1524559908444出来了1893883033


监听多线程超时

还记得介绍api的段落中那句“以及其他一些方法”吗?

Main类:

public class Main implements Runnable {
	
	//线程池
	public static final ExecutorService pool = Executors.newFixedThreadPool(3);
	
	@Override
	public void run() {
		FutureTask<String> task = new FutureTask<String>(new TestThread());
		new Thread(task).start();
		
		long start = System.currentTimeMillis();
		while (!task.isDone()) {
			long now = System.currentTimeMillis();
			if ((now - start) >= 3000) {//超时时间3000毫秒
				task.cancel(true);
				System.out.println(System.currentTimeMillis() + "线程超时了,打死他");
			}
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 3; i++) {
			pool.execute(new Main());
		}
	}
}

线程类:

public class TestThread implements Callable<String> {
	
	public static final ExecutorService pool = Executors.newFixedThreadPool(5);
	
	@Override
	public String call() {
		System.out.println(System.currentTimeMillis() + "进来了" + this.hashCode());
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {}
		
		return System.currentTimeMillis() + "出来了" + this.hashCode();
	}
}

来看看Main类的main方法执行结果

1524561058283进来了1966105457
1524561058283进来了227309514
1524561058283进来了120056986
1524561061283线程超时了,打死他
1524561061283线程超时了,打死他
1524561061283线程超时了,打死他
搞定~




猜你喜欢

转载自blog.csdn.net/yiyiwyf/article/details/80065413
今日推荐