使用Future停止超时任务
2013-03-10 00:35
429 查看
今天学了下多线程中超时任务的处理,这里和大家分享下,遇到了点问题没能解决,留下来希望大家帮我解疑啊。
在JAVA中停止线程的方法有多种,有一种是结合ExecutorService和Future的使用,停止在线程池中超时的任务。
这种情况下处理的都是比较耗时的操作,比如请求资源,数据库查询等,当超过一定时间没有返回结果,就结束线程,提高响应速度。
具体步骤如下:
实现Runnable接口或者Callable接口,分别实现run方法或者call方法,在方法中执行耗时操作。
将步骤1中的耗时操作线程放入到线程池中(通过ExecutorService.submit方法),这个线程池由ExecutorService来管理。
步骤2中的submit方法会返回一个Future对象,这个Future对象得到耗时操作的执行结果。Future的get(long timeout, TimeUnit unit)将会在指定的时间内去获得执行结果,如果操作还没执行完,就会抛出TimeoutException,在捕获这个超时异常时就可以取消耗时任务的执行(通过Future.
下面是一个下载大文件的程序,如果下载任务超时将关闭任务。
(DownloadTask.java: 下载任务)
注意到第4行定义了一个Throwable对象,这是因为在线程类的run方法中是没办法抛出异常的,要让外部获得程序的运行状况,就通过手动赋值和抛出,第45~49行定义了抛出异常的方法。(任务的业务逻辑不应该在内部处理掉,而应该在外部判断进行控制,个人理解)
(LoadSomething.java: 启动下载任务和处理异常)
第18行将下载任务放入了线程池中并且开始执行下载任务,第20行中在制定时间内去获得结果,如果超时将会抛出TimeoutException, 可以看到21行是抛出下载任务中所可能遇到的异常。最后在finally块中,调用future.cancle停掉任务。这里不用ExecutorService.shutdown方法是因为可能在线程池中有其他线程正在执行任务。
我遇到的问题:在33行中我加了个task.setStop(true)方法,这里通过改变控制变量状态来停止下载任务的执行,这种方法是可以停止掉下载任务。但是如果不用这种改变控制变量的方法,用future.cancel方法应该是能停掉下载任务的。但实际执行结果是抛出了超时异常,future.cancel返回了true,即任务已取消,但文件还是会继续下载下来,我想会不会是这样,文件下载是IO阻塞的,当下载任务执行的时候,线程会阻塞在那里,所以关不掉??希望知道的朋友指点一下我啊。
(LoadTest.java: 测试主函数)
程序运行结果:
源文件:
抛出异常:
目标文件:
之前对相对路径和绝对路径不是很了解,今天查了一下,有几篇好文章,个人觉得挺不错,也和大家分享下:
JAVA中的相对路径和绝对路径(和虚拟机JVM有关)
问题我已经找到答案了:
在java库中,许多可阻塞的方法都是通过提前返回或者抛出InterruptedException来响应中断请求的,从而使开发人员更容易构建出能响应取消请求的任务。然而并非所有的可阻塞方法或者阻塞机制都能响应中断;如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。
在服务应用程序中,最常见的阻塞I/O形式就是对套接字进行读取和写入。虽然InputStream和fOutputStream中的read和write等方法都不会响应中断,但通过关闭底层的套接字,可以使得由于执行read和write等方法而被阻塞的线程抛出一个socketException。
上面的情况和这个是类似的。
在JAVA中停止线程的方法有多种,有一种是结合ExecutorService和Future的使用,停止在线程池中超时的任务。
这种情况下处理的都是比较耗时的操作,比如请求资源,数据库查询等,当超过一定时间没有返回结果,就结束线程,提高响应速度。
具体步骤如下:
实现Runnable接口或者Callable接口,分别实现run方法或者call方法,在方法中执行耗时操作。
将步骤1中的耗时操作线程放入到线程池中(通过ExecutorService.submit方法),这个线程池由ExecutorService来管理。
步骤2中的submit方法会返回一个Future对象,这个Future对象得到耗时操作的执行结果。Future的get(long timeout, TimeUnit unit)将会在指定的时间内去获得执行结果,如果操作还没执行完,就会抛出TimeoutException,在捕获这个超时异常时就可以取消耗时任务的执行(通过Future.
cancel(true)).
下面是一个下载大文件的程序,如果下载任务超时将关闭任务。
(DownloadTask.java: 下载任务)
class DownloadTask implements Runnable { private String filename; // 接收在run方法中捕获的异常,然后自定义方法抛出异常 private Throwable exception; //是否关闭此下载任务 private boolean isStop = false; public void setStop(boolean isStop) { this.isStop = isStop; } public DownloadTask(String filename) { this.filename = filename; } /** * 下载大数据 * * @param filename * @throws FileNotFoundException * , IOException */ private void download() throws FileNotFoundException, IOException { File file = new File(filename); File saveFile = null; String[] names = filename.split("/"); String saveName = names[names.length - 1]; saveFile = new File("tmp/" + saveName); InputStream input = new FileInputStream(file); OutputStream output = new FileOutputStream(saveFile); // 进行转存 int len = 0; byte[] buffer = new byte[1024]; while (-1 != (len = input.read(buffer, 0, buffer.length))) { if(isStop) break; output.write(buffer, 0, len); } input.close(); output.close(); } public void throwException() throws FileNotFoundException, IOException { if (exception instanceof FileNotFoundException) throw (FileNotFoundException) exception; if (exception instanceof IOException) throw (IOException) exception; } @Override public void run() { try { download(); } catch (FileNotFoundException e) { exception = e; } catch (IOException e) { exception = e; } } }
注意到第4行定义了一个Throwable对象,这是因为在线程类的run方法中是没办法抛出异常的,要让外部获得程序的运行状况,就通过手动赋值和抛出,第45~49行定义了抛出异常的方法。(任务的业务逻辑不应该在内部处理掉,而应该在外部判断进行控制,个人理解)
(LoadSomething.java: 启动下载任务和处理异常)
/** * 使用Futrue来取消任务,模拟下载文件超时时取消任务 * * @author hongjie * */ public class LoadSomething { // 线程池服务接口 private ExecutorService executor; public LoadSomething() { executor = Executors.newSingleThreadExecutor(); } public void beginToLoad(DownloadTask task, long timeout, TimeUnit timeType) { Future<?> future = executor.submit(task); try { future.get(timeout, timeType); task.throwException(); } catch (InterruptedException e) { System.out.println("下载任务已经取消"); } catch (ExecutionException e) { System.out.println("下载中发生错误,请重新下载"); } catch (TimeoutException e) { System.out.println("下载超时,请更换下载点"); } catch (FileNotFoundException e) { System.out.println("请求资源找不到"); } catch (IOException e) { System.out.println("数据流出错"); } finally { task.setStop(true); // 因为这里的下载测试不用得到返回结果,取消任务不会影响结果 future.cancel(true); } } }
第18行将下载任务放入了线程池中并且开始执行下载任务,第20行中在制定时间内去获得结果,如果超时将会抛出TimeoutException, 可以看到21行是抛出下载任务中所可能遇到的异常。最后在finally块中,调用future.cancle停掉任务。这里不用ExecutorService.shutdown方法是因为可能在线程池中有其他线程正在执行任务。
我遇到的问题:在33行中我加了个task.setStop(true)方法,这里通过改变控制变量状态来停止下载任务的执行,这种方法是可以停止掉下载任务。但是如果不用这种改变控制变量的方法,用future.cancel方法应该是能停掉下载任务的。但实际执行结果是抛出了超时异常,future.cancel返回了true,即任务已取消,但文件还是会继续下载下来,我想会不会是这样,文件下载是IO阻塞的,当下载任务执行的时候,线程会阻塞在那里,所以关不掉??希望知道的朋友指点一下我啊。
(LoadTest.java: 测试主函数)
public class LoadTest { public static void main(String[] args) { LoadSomething load = new LoadSomething(); DownloadTask downloadTask = new DownloadTask("G:/Games/5211install.exe"); //开始下载,并设定超时限额为3毫秒 load.beginToLoad(downloadTask, 3, TimeUnit.MILLISECONDS); } }
程序运行结果:
源文件:
抛出异常:
目标文件:
之前对相对路径和绝对路径不是很了解,今天查了一下,有几篇好文章,个人觉得挺不错,也和大家分享下:
JAVA中的相对路径和绝对路径(和虚拟机JVM有关)
问题我已经找到答案了:
在java库中,许多可阻塞的方法都是通过提前返回或者抛出InterruptedException来响应中断请求的,从而使开发人员更容易构建出能响应取消请求的任务。然而并非所有的可阻塞方法或者阻塞机制都能响应中断;如果一个线程由于执行同步的Socket I/O或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。
在服务应用程序中,最常见的阻塞I/O形式就是对套接字进行读取和写入。虽然InputStream和fOutputStream中的read和write等方法都不会响应中断,但通过关闭底层的套接字,可以使得由于执行read和write等方法而被阻塞的线程抛出一个socketException。
上面的情况和这个是类似的。
相关文章推荐
- jenkins设置任务超时 超过限定时间停止任务
- C# 使用Task实现任务超时,多任务一起执行
- 使用linux计划任务自动拉起停止的通达OA服务apache和mysql服务
- ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,ES transport client可以同步调用也可以异步(不过底层的socket必然是异步实现)
- 使用linux计划任务自动拉起停止的通达OA服务apache和mysql服务
- 使用Future的cancel()方法来取消已经提交给执行者的任务
- [并发并行]_[任务停止]_[使用Pthread的线程本地存储来停止任务执行]
- 多线程任务Callable与Future或FutureTask的使用
- 牛刀小试:使用Reactive Extensions(Rx),一行代码实现多线程任务执行规定时间后自动停止
- java自定义任务类定时执行任务示例 callable和future接口使用方法
- Android 异步任务 设置 超时使用handler更新通知功能
- 线程死锁,使用Future捕获死锁超时
- java自定义任务类定时执行任务示例 callable和future接口使用方法
- Spring Boot利用@Async异步调用:使用Future及定义超时详解
- Java并发编程——线程池的使用(七)线程池的可执行任务:Future和Callable
- Java使用Future设置方法超时
- java系统中使用调度器Quartz实现对正在执行任务的停止
- [Jenkins]如何自动停止超时任务?
- java 超时任务---设定任务执行时长,超时停止
- 牛刀小试:使用Reactive Extensions(Rx),一行代码实现多线程任务执行规定时间后自动停止