`
wangwengcn
  • 浏览: 175806 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

任务取消与关闭(interrupt)

阅读更多

虽然Thread.stop和suspend等方法提供了线程终止的机制,但由于存在一些严重的缺陷,因此应该避免使用。可以说Java并没有提供任何机制来安全地终止线程。但它提供了中断(Interrupt),这时一种协作机制,能够使一个线程终止另一个线程的当前工作。
提到中断,我们就不得不说明一下Thead.interrupt方法:调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。
请看下面一个程序:

Thread t = new Thread(new Runnable(){
			@Override
			public void run() {
				long i = 0;
				while(true)
				{
					System.out.println(i++);
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						System.out.println(Thread.currentThread().isInterrupted());
						Thread.currentThread().interrupt();
						System.out.println(Thread.currentThread().isInterrupted());
						e.printStackTrace();
					}
				}
			}
		});
		t.start();
		try {
			Thread.sleep(3000);
			t.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

 

哪怕在主线程中调用了t.interrupt()这个方法,但是t线程并不会停止执行,还是会无线执行下去。因为这个方法只是发送了一个消息给t线程,而t线程内部也只是将该线程的状态设置为了中断,这个状态可以通过Thead.isInterrupted或者静态方法interrupted来得到(如果已经中断,那么得到的是true)。
对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己


关于中断有两个地方需要注意:

  • 一是捕获了InterruptedException异常,在JVM内部捕获到该异常以后会马上清除中断状态,也就是说调用Thead.isInterrupted得到将会是false
  • 二是调用了静态方法interrupted,这个静态方法也会清除中断状态,如果仅仅要得到当前的状态信息,请使用Thead.isInterrupted

需要注意:只有当线程在阻塞状态下发生中断时,才会抛出InterruptedException异常,这里所说的阻塞状态包括三种情况:

  1. wait
  2. sleep
  3. join

在非阻塞状态下中断时,仅仅它的中断状态会被设置,并不会触发InterruptedException异常,这里和别的异常不一样,你要是在非阻塞状态下手工捕获这个异常,编译是通不过的。会提示:Unreachable catch block for InterruptedException. This exception is never thrown from the try statement body。 而捕获别的异常不会有这种情况。
这时候你就要在线程中自己来判断中断状态,比如下面这个程序,在每次循环的开始部分都判断当前的中断状态,当状态改变时,线程结束:

Runnable task = new Runnable() {
			
			@Override
			public void run() {
				while(!Thread.currentThread().isInterrupted())
				{
					System.out.println(1);
				}
			}
		};

 通常,中断是实现取消的最合理方式,不要使用boolean标志来请求取消。

 

有人会说了,interrupt方法是Thread的方法,而我们在使用Executor框架执行任务的时候经常会使用Runnable。这时,我们就无法使用中断方法来取消了。这个时候我们可以使用Future来实现取消,查看API你会发现Future有一个cancel方法,再去查看源码,下面是cancle方法的内部实现:

 

boolean innerCancel(boolean mayInterruptIfRunning) {
	    for (;;) {
		int s = getState();
		if (ranOrCancelled(s))
		    return false;
		if (compareAndSetState(s, CANCELLED))
		    break;
	    }
            if (mayInterruptIfRunning) {
                Thread r = runner;
                if (r != null)
                    r.interrupt();
            }
            releaseShared(0);
            done();
            return true;
        }

 我们可以发现,它也是通过中断线程来实现的,所以要真正的取消任务还是要在每个任务中实现自己的中断策略。
因此:由于每个线程拥有各自的中断策略,因此除非你直到中断对该线程的含义,否则就不应该中断这个线程。没有实现中断策略的任务哪怕你调了cancel方法也是无法中断这个线程的。比如下面这个非阻塞任务(阻塞任务必定会抛出InterruptedException,一般都会实现中断策略的):

ExecutorService executorService = Executors.newFixedThreadPool(10);
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				while(true)
				{
					System.out.println(1);
				}
			}
		};
		
		Future<?> future = executorService.submit(task);
		Thread.sleep(2000);
		future.cancel(true);

 这个程序哪怕被cancel了,其实也是一直会print出字符的。

你可以这么写,在规定的三秒钟之内没有执行完任务(这个程序只要不中断,必然不会执行完,是一个死循环),那么主线程就会取消它:
ExecutorService executorService = Executors.newFixedThreadPool(10);
		Runnable task = new Runnable() {
			
			@Override
			public void run() {
				while(!Thread.currentThread().isInterrupted())
				{
					System.out.println(1);
				}
			}
		};
		
		Future<?> future = executorService.submit(task);
		try {
			future.get(3, TimeUnit.SECONDS);
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
		finally{
			future.cancel(true);
		}
 
分享到:
评论

相关推荐

    JAVA并发编程实践-线程的关闭与取消-学习笔记

    在Java并发编程中,线程的关闭和取消是一项重要的任务,因为不正确的处理可能导致数据不一致、资源泄漏等问题。在Java中,强制停止线程并不是一个推荐的做法,因为这可能会导致系统状态的不稳定。传统的`Thread.stop...

    xiaopeng.rar_S3C6410 INTERRUPT

    在嵌入式系统开发中,中断驱动程序是操作系统与硬件交互的关键部分,它使得硬件能够及时、高效地向处理器发送事件通知。S3C6410是一款由Samsung生产的高性能ARM11架构的微处理器,广泛应用于嵌入式设备中。在本主题...

    Exp2-ARM-serial-interrupt.zip_linux 串口中断

    "Exp2-ARM-serial-interrupt.zip" 文件包含了一个ARM架构下实现串口中断的实验,下面将详细介绍相关的知识点。 1. **串口通信**: - **UART(通用异步收发传输器)**:是串口通信的基础,负责将并行数据转换为串行...

    Android线程结束——合理的结束你想结束的线程

    3. **取消与重试策略**:如果任务需要取消,可以考虑设计重试机制,让任务在合适的时候重新启动。 4. **理解生命周期**:AsyncTask与Activity的生命周期紧密关联。当Activity结束时,应取消相关的AsyncTask,以防止...

    Java线程超时监控

    否则,它将抛出一个`TimeoutException`,此时可以取消任务。 另外,`java.lang.Thread`类也提供了一种实现线程超时的方法,通过使用`join`方法。`join`可以等待某个线程结束,同时可以设置一个等待时限。 ```java ...

    java通过线程控制程序执行超时(新)

    Future对象可以用来检查任务是否完成,如果超过预定时间,可以调用`cancel()`方法来取消任务。 ```java ExecutorService executor = Executors.newSingleThreadExecutor(); Future&lt;String&gt; future = executor....

    concurrent-all-in-one.pdf

    - 取消任务:`cancel()`方法尝试取消任务,如果任务已经开始则可能无法取消。 6. **ExecutorService管理** - 创建:`Executors`工厂类提供多种ExecutorService实例。 - 分配任务:使用`execute()`方法提交...

    rg_interrupt

    "rg_interrupt"这个主题可能指的是一个特定的项目或者库,它与Python编程语言中的中断处理有关。在Python中,处理中断(例如键盘中断Ctrl+C)通常涉及到异常处理和线程管理。 在Python中,中断通常是通过`...

    11-线程池ThreadPoolExecutor底层原理源码分析(上)-周瑜.pdf

    2. **`submit(Runnable task)`**:这个方法同样用于提交一个`Runnable`任务,但它返回一个`Future`对象,可以通过该对象来获取任务执行的结果或取消任务的执行。 ### `execute()`方法的执行流程 当调用`execute()`...

    处理 InterruptedException1

    但是,这种方法忽略了这样一个事实:这期间可能发生中断,而中断可能导致应用程序丧失及时取消活动或关闭的能力。因此,正确地处理 InterruptedException 是非常重要的。 中断状态是每个线程都有的一个 Boolean ...

    Go-在Go中实现在不中断服务的情况下优雅重启

    - 通常,我们会为每个goroutine提供一个可以被关闭的`context.Context`,当需要停止服务时,通过这个`Context`来取消任务。 - 示例代码: ```go func startService() { ctx, cancel := context.WithCancel...

    Android Studio —— Thread

    当一个线程需要被取消时,可以调用interrupt方法。然而,线程本身需要检查并响应中断状态,以确保正确关闭。 10. **ThreadLocal** ThreadLocal是Java提供的一个线程局部变量,每个线程都有自己的副本,互不影响,...

    中断服务下半部之工作队列详解

    中断服务上半部(Interrupt Service Routine,ISR)是中断发生时立即执行的代码,它的主要任务是保存现场、关闭中断、识别中断源并做一些快速的、必须在原子操作下完成的处理。然而,有些操作不适合在ISR中执行,...

    RTAI文档.源代码说明.pdf

    综上所述,RTAI文档中的源代码说明部分详细阐述了RTAI在x86架构下如何进行中断处理、中断的启动和关闭、中断源的管理,以及如何与标准Linux内核集成的一系列API函数。同时,文档强调了RTAI作为开源软件的许可条款和...

    几种方法编写线程代码

    `Future`接口代表`Callable`任务的结果,可以检查任务是否完成,获取结果或取消任务。例如: ```java ExecutorService executor = Executors.newSingleThreadExecutor(); Future&lt;Integer&gt; future = executor.submit...

    android安卓app如何彻底结束进程. 光调用finish()是结束不了程序的,程序中的线程依旧在后台运行.zip

    这样,当新Activity关闭时,整个任务栈都会被清理,从而结束应用进程。 在实际开发中,除非有特殊需求,否则通常不建议强行结束应用进程,因为Android系统会根据资源需求自动管理进程。过度干预可能会导致系统不...

    Go中优雅的进程重启_Go_下载.zip

    使用`context.Context`可以帮助管理上下文和取消信号,而`net/http.Server`提供了优雅停机的选项,可以在接收到信号后等待已接收的请求完成后再关闭服务器。 总之,优雅的进程重启是维持服务稳定性的重要手段,它...

    终止线程的源代码资源

    - **Future/Tasks**:使用ExecutorService提交任务,调用Future的cancel()方法请求取消,线程会尝试停止。 5. **线程池与线程终止** - **ThreadPoolExecutor**:可以设置核心线程存活策略、最大线程数、超时策略...

    Java并发编程示例(三):线程中断

    在实际的并发编程中,线程中断常用于取消任务、响应外部事件或者优雅地关闭资源。它与`Thread.stop()`方法不同,后者是不推荐使用的,因为它可能导致数据损坏和死锁。线程中断是一种更加安全和推荐的方式来控制线程...

Global site tag (gtag.js) - Google Analytics