java 多线程之取消与关闭

  要使线程安全,快速,可靠的停下来并不是一件容易的事情。java并没有提供任何机制来安全的终止线程。但是java提供了中断(interrupt)使一个线程可以终止另一个线程的当前工作

  每个线程都有一个boolean类型的中断状态。当中断线程时,这个线程的中断状态将被设置未true。Thread包含了中断线程以及检查线程中断的方法。

 

    interrupt()方法能中断目标线程。

    boolean isInterrupt()方法能返回目标线程是否中断的状态。

    static boolean interrupted() 将返回并清除线程当前的中断状态,这个也是清除线程中断状态的唯一方法。

 

  调用interrupt()方法并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。然后由线程在下一个合适的时机中断自己。

  中断策略

  每个线程都应该包含自己的终端策略,以响应中断状态。中断策略规定了线程如何响应中断请求-----当发现中断请求时应该做哪些操作,哪些工作单元对中断来说是原子的,以及以多块的速度相应中断。

   响应中断

  当调用可中断的阻塞函数时有两种使用策略可用于处理interruption异常

    1.传递异常,从而使你的方法也变成可中断的阻塞方法。

      传递异常只需要在方法外加上 throws interruptedException就可以了,

    2.恢复中断状态,从而使调用栈中的上层代码能够对其进行处理。

      可以调用interrupt()方法来恢复中断状态。

  二. 如果代码不会调用可中断的阻塞方法,那么仍然可以通过轮询当前线程中的中断状态来相应中断。

 

  通过Future实现取消

  调用ExecutorService.submit方法将返回一个future对象。

  Future.cancel(boolean b).可用于取消当前任务。若b设置为true,则表示若线程正在运行则中断,若设置为false,若还没有运行则不会运行,则表示若正在运行就不中断,还未运行就不在执行。返回值只是表示是否设置中断状态成功,而不是线程已经中断。

 

  处理不可中断的阻塞

  java.io包中的同步socket,io,可直接关闭底层socket套接字。

  java.io可关闭链路

  selector异步io可调用close或wakeup方法提前返回。

 

  关闭基于线程的服务

  应用程序通常创建拥有多个线程的服务。这些服务的生命周期通常比创建他们的方法要长,如果应用程序准备退出,那么服务拥有的线程也需要结束,因此服务应该提供生命周期方法,来关闭它自己以及它所拥有的线程。

  ExecutorService就提供了shutdown和shutdownnow两个方法来停止服务。shutdownnow方法会首先停止接受新的任务,然后关闭正在执行的任务,最后返回已经提交单还没有执行的任务。而shutdown方法会首先停止接受新的任务,然后等待队列中所有已经提交的任务完成,最后执行关闭。shutdownnow拥有更好的响应性但安全性较差。

  另一种关闭生产者---消费者服务的方式是使用毒丸对象。只有在生产者和消费者数量都已知的情况下才可以使用毒丸对象。并且只有在无界队列中毒丸对象才能正常的工作。而且当生产者和消费者数量都很大时,这种方法将变的难以使用。

 

  处理非正常的线程终止

  1.通过主动的方式处理。在任务处理线程的生命周期中,将通过某种抽象机制来调用许多未知的代码,我们应该对这些线程中执行的代码能否表现出正确的行为表示怀疑,因此这些线程应该在try-catch代码块中执行,这样就能捕获那些未检查的异常了,或者可以在try-finally代码块确保框架能够知道线程非正常退出的情况,并做出正确的相应。

  2.通过ThreadAPI提供的UncaughtExceptionHandler处理。UncaughtExceptionHandler能够检测出某个线程由于未补获异常而终止的情况。只有通过execute方法提交的任务才能将异常交给未补获异常处理器处理,通过submit提交的方法,无论时抛出检查的还是未检查的异常都将视为是任务返回状态的一部分。如果一个由submit提交的任务抛出了异常,那么这个异常将会被Future.get封装在ExecueExcetion中重新抛出。

  这两种方法时互补的,通过将这两种方法有效的结合在一起就能有效的防止线程泄露的问题。

 

posted on 2018-07-03 22:51  monkeydai  阅读(1570)  评论(0编辑  收藏  举报

导航