`
arison1983
  • 浏览: 28391 次
  • 性别: Icon_minigender_1
  • 来自: 新疆
最近访客 更多访客>>
社区版块
存档分类

Java怎样中断一个运行中的线程

阅读更多

Java怎样中断一个运行中的线程

原文地址:http://www.java8.net

本文详细介绍Java怎样中断一个运行中的线程,希望通过本文的学习,能对你有所帮助。

  程序是很简易的。然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的、难以发现的错误。

  在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程。

   背景中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。线程是死亡、还是等待新的任务或是 继续运行至下一步,就取决于这个程序。虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果。你最好还是牢记以下的几点告诫。

  首先,忘掉Thread.stop方法。虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的JAVA版本中,它将不复存在。

   一些轻率的家伙可能被另一种方法Thread.interrupt所迷惑。尽管,其名称似乎在暗示着什么,然而,这种方法并不会中断一个正在运行的线程 (待会将进一步说明),正如Listing A中描述的那样。它创建了一个线程,并且试图使用Thread.interrupt方法停止该线程。 Thread.sleep()方法的调用,为线程的初始化和中止提供了充裕的时间。线程本身并不参与任何有用的操作。

 

class Example1 extends Thread {
      boolean stop=false;
      public static void main( String args[] ) throws Exception {
      Example1 thread = new Example1();
      System.out.println( "Starting thread..." );
      thread.start();
      Thread.sleep( 3000 );
      System.out.println( "Interrupting thread..." );
      thread.interrupt();
      Thread.sleep( 3000 );
      System.out.println("Stopping application..." );
      //System.exit(0);
      }
      public void run() {
      while(!stop){
      System.out.println( "Thread is running..." );
      long time = System.currentTimeMillis();
      while((System.currentTimeMillis()-time < 1000)) {
      }
      }
      System.out.println("Thread exiting under request..." );
      }
      }

 

  如果你运行了Listing A中的代码,你将在控制台看到以下输出:

Starting thread...
Thread is running...
Thread is running...
Thread is running...
Interrupting thread...
Thread is running...
Thread is running...
Thread is running...
Stopping application...
Thread is running...
Thread is running...
Thread is running...
...............................

 

 甚至,在Thread.interrupt()被调用后,线程仍然继续运行。

  真正地中断一个线程

  中断线程最好的,最受推荐的方式是,使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。线程必须周期性的核查这一变量(尤其在冗余操作期间),然后有秩序地中止任务。Listing B描述了这一方式。

/*Listing B*/
class Example2 extends Thread {
 volatile boolean stop = false;
 public static void main( String args[] ) throws Exception {
  Example2 thread = new Example2();
  System.out.println( "Starting thread..." );
  thread.start();
  Thread.sleep( 3000 );
  System.out.println( "Asking thread to stop..." );
  thread.stop = true;
  Thread.sleep( 3000 );
  System.out.println( "Stopping application..." );
  //System.exit( 0 );
 }
 public void run() {
  while ( !stop ) {
   System.out.println( "Thread is running..." );
   long time = System.currentTimeMillis();
   while ( (System.currentTimeMillis()-time < 1000) && (!stop) ) {
   }
  }
  System.out.println( "Thread exiting under request..." );
 }
}

   运行Listing B中的代码将产生如下输出(注意线程是如何有秩序的退出的)

 

Starting thread...
Thread is running...
Thread is running...
Thread is running...
Asking thread to stop...
Thread exiting under request...
Stopping application...

 

 虽然该方法要求一些编码,但并不难实现。同时,它给予线程机会进行必要的清理工作,这在任何一个多线程应用程序中都是绝对需要的。请确认将共享变 量定义成volatile 类型或将对它的一切访问封入同步的块/方法(synchronized blocks/methods)中。

   到目前为止一切顺利!但是,当线程等待某些事件发生而被阻塞,又会发生什么?当然,如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况 下会发生,例如调用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,这 里仅举出一些。

  他们都可能永久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使用某种机制使得线程更早地退出被阻塞的状态。

  很不幸运,不存在这样一种机制对所有的情况都适用,但是,根据情况不同却可以使用特定的技术。在下面的环节,我将解答一下最普遍的例子。

  使用Thread.interrupt()中断线程

   正如Listing A中所描述的,Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样 线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和 Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。

 

 

 

  因此,如果线程被上述几种方法阻塞,正确的停止线程方式是设置共享变量,并调用interrupt()(注意变量应该先设置)。如果线程没有被阻塞, 这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最后线程 都将检查共享变量然后再停止。Listing C这个示例描述了该技术。

 

/*Listing C*/
class Example3 extends Thread {
 volatile boolean stop = false;
 public static void main( String args[] ) throws Exception {
  Example3 thread = new Example3();
  System.out.println( "Starting thread..." );
  thread.start();
  Thread.sleep( 3000 );
  System.out.println( "Asking thread to stop..." );
  thread.stop = true;//如果线程阻塞,将不会检查此变量
  thread.interrupt();
  Thread.sleep( 3000 );
  System.out.println( "Stopping application..." );
  //System.exit( 0 );
 }
 public void run() {
  while ( !stop ) {
   System.out.println( "Thread running..." );
   try {
   Thread.sleep( 1000 );
   } catch ( InterruptedException e ) {
   System.out.println( "Thread interrupted..." );
   }
  }
  System.out.println( "Thread exiting under request..." );
 }
}

 

 一旦Listing C中的Thread.interrupt()被调用,线程便收到一个异常,于是逃离了阻塞状态并确定应该停止。运行以上代码将得到下面的输出:

 

Starting thread...
Thread running...
Thread running...
Thread running...
Asking thread to stop...
Thread interrupted...
Thread exiting under request...
Stopping application...
 

  中断I/O操作

  然而,如果线程在I/O操作进行时被阻塞,又会如何?I/O操作可以阻塞线程一段相当长的时间,特别是牵扯到网络应用时。例如,服务器可能需要等待一个请求(request),又或者,一个网络应用程序可能要等待远端主机的响应。

  如果你正使用通道(channels)(这是在Java 1.4中引入的新的I/O API),那么被阻塞的线程将收到一个 ClosedByInterruptException异常。如果情况是这样,其代码的逻辑和第三个例子中的是一样的,只是异常不同而已。

   但是,你可能正使用Java1.0之前就存在的传统的I/O,而且要求更多的工作。既然这样,Thread.interrupt()将不起作用,因为线 程将不会退出被阻塞状态。Listing D描述了这一行为。尽管interrupt()被调用,线程也不会退出被阻塞状态。

 

Listing D
import java.io.*;
class Example4 extends Thread {
 public static void main( String args[] ) throws Exception {
  Example4 thread = new Example4();
  System.out.println( "Starting thread..." );
  thread.start();
  Thread.sleep( 3000 );
  System.out.println( "Interrupting thread..." );
  thread.interrupt();
  Thread.sleep( 3000 );
  System.out.println( "Stopping application..." );
  //System.exit( 0 );
 }
 public void run() {
  ServerSocket socket;
  try {
   socket = new ServerSocket(7856);
  } catch ( IOException e ) {
   System.out.println( "Could not create the socket..." );
   return;
  }
  while ( true ) {
   System.out.println( "Waiting for connection..." );
   try {
    Socket sock = socket.accept();
   } catch ( IOException e ) {
   System.out.println( "accept() failed or interrupted..." );
   }
  }
 }
}
 

 

  很幸运,Java平台为这种情形提供了一项解决方案,即调用阻塞该线程的套接字的close()方法。在这种情形下,如果线程被I/O操作阻 塞,该线程将接收到一个SocketException异常,这与使用interrupt()方法引起一个InterruptedException异常 被抛出非常相似。

  唯一要说明的是,必须存在socket的引用(reference),只有这样close()方法才能被调用。这意味着socket对象必须被共享。Listing E描述了这一情形。运行逻辑和以前的示例是相同的。

/*Listing E*/
import java.net.*;
import java.io.*;
class Example5 extends Thread {
 volatile boolean stop = false;
 volatile ServerSocket socket;
 public static void main( String args[] ) throws Exception {
  Example5 thread = new Example5();
  System.out.println( "Starting thread..." );
  thread.start();
  Thread.sleep( 3000 );
  System.out.println( "Asking thread to stop..." );
  thread.stop = true;
  thread.socket.close();
  Thread.sleep( 3000 );
  System.out.println( "Stopping application..." );
  //System.exit( 0 );
 }
 public void run() {
  try {
   socket = new ServerSocket(7856);
  } catch ( IOException e ) {
   System.out.println( "Could not create the socket..." );
   return;
  }
  while ( !stop ) {
   System.out.println( "Waiting for connection..." );
   try {
    Socket sock = socket.accept();
   } catch ( IOException e ) {
   System.out.println( "accept() failed or interrupted..." );
   }
  }
  System.out.println( "Thread exiting under request..." );
 }
}

 

    以下是运行Listing E中代码后的输出:

Starting thread...
Waiting for connection...
Asking thread to stop...
accept() failed or interrupted...
Thread exiting under request...
Stopping application...

   多线程是一个强大的工具,然而它正呈现出一系列难题。其中之一是如何中断一个正在运行的线程。如果恰当地实现,使用上述技术中断线程将比使用Java平台上已经提供的内嵌操作更为简单。

-----------------------------------------------------終了

分享到:
评论

相关推荐

    java多线程Demo

    Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新...

    Java如何中断一个正在运行的线程

    Java如何中断一个正在运行的线程 Java中的线程中断是指在某个线程完成任务之前停止其正在进行的...本文对Java中断一个正在运行的线程进行了详细的介绍和分析,旨在帮助读者更好地理解和掌握线程中断的知识和技能。

    java中 如何终止一个线程

    ### Java中如何安全地终止一个线程 在Java编程中,正确且安全地终止线程是非常重要的,因为不当的操作可能会导致资源泄露、数据不一致性甚至系统崩溃等问题。本篇文章将详细探讨如何使用`interrupt()`方法安全地...

    Java如何中断一个正在运行的线程[整理].pdf

    在Java编程中,多线程是并发执行任务的关键机制,但同时也带来了许多挑战,其中之一就是如何安全地中断一个正在运行的线程。本篇文章主要探讨了如何正确地中断线程,避免潜在的问题。 首先,我们要明确一点:Java中...

    Java多线程机制(讲述java里面与多线程有关的函数)

    每个Java程序都有一个主线程,即由JVM启动并执行main方法的线程。线程代表了程序中的执行流,可以在不同的线程之间切换以共享CPU时间。线程的状态包括新建、运行、中断和死亡。线程的生命周期始于新建,通过调用...

    JAVA 线程中启动线程

    - **yield()**:让当前线程暂停,给其他可运行线程一个执行机会,但不保证一定能切换。 - **interrupt()**:中断线程,标记线程的中断状态,对于阻塞操作(如sleep、wait)会抛出`InterruptedException`。 4. **...

    java 查看JVM中所有的线程的活动状况

    在Java编程环境中,了解JVM(Java虚拟机)中所有线程的活动状态对于调试多线程程序至关重要。本文将详细讲解如何查看JVM中的线程活动情况,并提供相关示例代码。 首先,Java提供了`java.lang.management....

    java多线程的讲解和实战

    1. **线程的基本概念**:线程是程序执行的最小单位,一个进程中可以有多个线程同时运行。Java通过`Thread`类和`Runnable`接口来创建和管理线程。每个线程都有自己的生命周期,包括新建、就绪、运行、阻塞和结束五个...

    java中线程的应用例子

    5. **线程优先级**:每个线程都有一个优先级,Java中从1(`MIN_PRIORITY`)到10(`MAX_PRIORITY`),默认优先级是5(`NORM_PRIORITY`)。但优先级并不保证线程的执行顺序,它只是影响调度策略。 6. **线程池**:`...

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

    当一个线程运行时间过长,我们需要一种机制来中断它,这就是超时控制的目的。 超时控制通常可以通过两种方式实现:使用Future和Callable接口,或者使用中断机制。 1. Future和Callable接口: 当我们需要异步执行...

    另外一个java多线程下载程序源代码

    在这个“另外一个java多线程下载程序源代码”中,我们可以深入学习如何利用Java的多线程特性来创建一个高效的文件下载应用。 首先,我们了解Java中创建线程的两种主要方式: 1. 继承`Thread`类:自定义一个新的类...

    Java建立一个单线程的实例.rar

    创建一个单线程在Java中非常常见,特别是在处理并发问题时。这个实例将帮助初学者理解如何在Java中创建和管理单线程。下面我们将详细讨论相关知识点。 1. **线程的生命周期**: - 新建(New):当使用`Thread`类...

    Java多线程笔记

    在 Java 中,线程中断是通过 interrupt 方法来实现的,该方法只是给线程置一个中断标志位,并不会立即停止线程的运行。interrupted 方法可以判断是否被中断,静态方法 interrupted() 则可以判断是否被中断,并清除...

    Java线程.ppt

    Java线程是Java编程中的重要概念,特别是在多核处理器和并发处理中不可或缺。Java线程允许程序在同一时间执行多个不同的任务,从而提高了程序的效率和响应性。在燕山大学信息学院计算机系的课程中,李峰教授讲解了...

    Java线程详解大全

    线程是程序中一个单一的顺序控制流,它在程序的上下文中运行,但具有独立的执行路径。多线程则是指在单个程序内同时运行多个不同的线程,每个线程执行不同的任务。线程共享同一份程序内存空间,但拥有各自的程序...

    JAVA-多线程 所有文件

    Java提供了一个内置的多线程模型,使得开发者可以在一个程序中同时运行多个任务。 2. **创建线程**:在Java中,有两种主要方式创建线程:继承`Thread`类和实现`Runnable`接口。继承`Thread`类直接创建线程对象,而...

    java多线程示例

    在Java编程语言中,多线程是核心特性之一,它允许程序同时执行多个任务,从而提高了应用程序的效率和响应速度。本示例着重探讨如何在Java中实现和管理多线程,以及它带来的挑战和解决方案。 一、Java多线程基础 1. ...

    java多线程控制的赛跑程序

    这个“java多线程控制的赛跑程序”是一个示例,展示了如何利用多线程来模拟一场赛跑比赛。在这个程序中,每个参赛者(线程)都有自己的运行逻辑,通过线程的并发执行来模拟实际的赛跑过程。接下来,我们将深入探讨...

    Java的线程和Java AppletJava的线程和Java AppletJava的线程和Java Applet

    Java的线程和Java Applet是Java编程中的两个重要概念,它们分别涉及并发执行和Web应用程序的执行环境。 **线程**在Java中是程序执行的最小单元,它允许程序在同一时间执行多个任务。Java内置对多线程的支持,使得...

    Java线程超时监控

    在Java编程中,多线程是并发执行任务的重要方式,然而在实际应用中,我们可能会遇到某些线程执行时间过长或死锁的情况,这可能导致系统资源的浪费甚至整体性能下降。因此,对线程进行超时监控是必要的,以确保程序的...

Global site tag (gtag.js) - Google Analytics