`
trophy
  • 浏览: 176559 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

java 中断运行线程

    博客分类:
  • java
 
阅读更多

 

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

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

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

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

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

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

 

Java代码   收藏代码
  1. class Example1 extends Thread {  
  2.       boolean stop=false;  
  3.       public static void main( String args[] ) throws Exception {  
  4.       Example1 thread = new Example1();  
  5.       System.out.println( "Starting thread..." );  
  6.       thread.start();  
  7.       Thread.sleep( 3000 );  
  8.       System.out.println( "Interrupting thread..." );  
  9.       thread.interrupt();  
  10.       Thread.sleep( 3000 );  
  11.       System.out.println("Stopping application..." );  
  12.       //System.exit(0);  
  13.       }  
  14.       public void run() {  
  15.       while(!stop){  
  16.       System.out.println( "Thread is running..." );  
  17.       long time = System.currentTimeMillis();  
  18.       while((System.currentTimeMillis()-time < 1000)) {  
  19.       }  
  20.       }  
  21.       System.out.println("Thread exiting under request..." );  
  22.       }  
  23.       }  

 

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

Java代码   收藏代码
  1. Starting thread...  
  2. Thread is running...  
  3. Thread is running...  
  4. Thread is running...  
  5. Interrupting thread...  
  6. Thread is running...  
  7. Thread is running...  
  8. Thread is running...  
  9. Stopping application...  
  10. Thread is running...  
  11. Thread is running...  
  12. Thread is running...  
  13. ...............................  

 

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

  真正地中断一个线程

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

Java代码   收藏代码
  1. /*Listing B*/  
  2. class Example2 extends Thread {  
  3.  volatile boolean stop = false;  
  4.  public static void main( String args[] ) throws Exception {  
  5.   Example2 thread = new Example2();  
  6.   System.out.println( "Starting thread..." );  
  7.   thread.start();  
  8.   Thread.sleep( 3000 );  
  9.   System.out.println( "Asking thread to stop..." );  
  10.   thread.stop = true;  
  11.   Thread.sleep( 3000 );  
  12.   System.out.println( "Stopping application..." );  
  13.   //System.exit( 0 );  
  14.  }  
  15.  public void run() {  
  16.   while ( !stop ) {  
  17.    System.out.println( "Thread is running..." );  
  18.    long time = System.currentTimeMillis();  
  19.    while ( (System.currentTimeMillis()-time < 1000) && (!stop) ) {  
  20.    }  
  21.   }  
  22.   System.out.println( "Thread exiting under request..." );  
  23.  }  
  24. }  

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

 

Java代码   收藏代码
  1. Starting thread...  
  2. Thread is running...  
  3. Thread is running...  
  4. Thread is running...  
  5. Asking thread to stop...  
  6. Thread exiting under request...  
  7. 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这个示例描述了该技术。

 

Java代码   收藏代码
  1. /*Listing C*/  
  2. class Example3 extends Thread {  
  3.  volatile boolean stop = false;  
  4.  public static void main( String args[] ) throws Exception {  
  5.   Example3 thread = new Example3();  
  6.   System.out.println( "Starting thread..." );  
  7.   thread.start();  
  8.   Thread.sleep( 3000 );  
  9.   System.out.println( "Asking thread to stop..." );  
  10.   thread.stop = true;//如果线程阻塞,将不会检查此变量  
  11.   thread.interrupt();  
  12.   Thread.sleep( 3000 );  
  13.   System.out.println( "Stopping application..." );  
  14.   //System.exit( 0 );  
  15.  }  
  16.  public void run() {  
  17.   while ( !stop ) {  
  18.    System.out.println( "Thread running..." );  
  19.    try {  
  20.    Thread.sleep( 1000 );  
  21.    } catch ( InterruptedException e ) {  
  22.    System.out.println( "Thread interrupted..." );  
  23.    }  
  24.   }  
  25.   System.out.println( "Thread exiting under request..." );  
  26.  }  
  27. }  

 

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

 

Java代码   收藏代码
  1. Starting thread...  
  2. Thread running...  
  3. Thread running...  
  4. Thread running...  
  5. Asking thread to stop...  
  6. Thread interrupted...  
  7. Thread exiting under request...  
  8. 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()被调用,线程也不会退出被阻塞状态。

 

Java代码   收藏代码
  1. Listing D  
  2. import java.io.*;  
  3. class Example4 extends Thread {  
  4.  public static void main( String args[] ) throws Exception {  
  5.   Example4 thread = new Example4();  
  6.   System.out.println( "Starting thread..." );  
  7.   thread.start();  
  8.   Thread.sleep( 3000 );  
  9.   System.out.println( "Interrupting thread..." );  
  10.   thread.interrupt();  
  11.   Thread.sleep( 3000 );  
  12.   System.out.println( "Stopping application..." );  
  13.   //System.exit( 0 );  
  14.  }  
  15.  public void run() {  
  16.   ServerSocket socket;  
  17.   try {  
  18.    socket = new ServerSocket(7856);  
  19.   } catch ( IOException e ) {  
  20.    System.out.println( "Could not create the socket..." );  
  21.    return;  
  22.   }  
  23.   while ( true ) {  
  24.    System.out.println( "Waiting for connection..." );  
  25.    try {  
  26.     Socket sock = socket.accept();  
  27.    } catch ( IOException e ) {  
  28.    System.out.println( "accept() failed or interrupted..." );  
  29.    }  
  30.   }  
  31.  }  
  32. }  

 

 

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

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

Java代码   收藏代码
  1. /*Listing E*/  
  2. import java.net.*;  
  3. import java.io.*;  
  4. class Example5 extends Thread {  
  5.  volatile boolean stop = false;  
  6.  volatile ServerSocket socket;  
  7.  public static void main( String args[] ) throws Exception {  
  8.   Example5 thread = new Example5();  
  9.   System.out.println( "Starting thread..." );  
  10.   thread.start();  
  11.   Thread.sleep( 3000 );  
  12.   System.out.println( "Asking thread to stop..." );  
  13.   thread.stop = true;  
  14.   thread.socket.close();  
  15.   Thread.sleep( 3000 );  
  16.   System.out.println( "Stopping application..." );  
  17.   //System.exit( 0 );  
  18.  }  
  19.  public void run() {  
  20.   try {  
  21.    socket = new ServerSocket(7856);  
  22.   } catch ( IOException e ) {  
  23.    System.out.println( "Could not create the socket..." );  
  24.    return;  
  25.   }  
  26.   while ( !stop ) {  
  27.    System.out.println( "Waiting for connection..." );  
  28.    try {  
  29.     Socket sock = socket.accept();  
  30.    } catch ( IOException e ) {  
  31.    System.out.println( "accept() failed or interrupted..." );  
  32.    }  
  33.   }  
  34.   System.out.println( "Thread exiting under request..." );  
  35.  }  
  36. }  

 

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

Java代码   收藏代码
  1. Starting thread...  
  2. Waiting for connection...  
  3. Asking thread to stop...  
  4. accept() failed or interrupted...  
  5. Thread exiting under request...  
  6. Stopping application...  

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

 

分享到:
评论

相关推荐

    Java-并发-Java线程中断与停止线程详解

      Java 中的线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理。即“线程中断”并不是字面意思——线程真的中断了,而是设置了中断标志...

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

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

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

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

    java中终止一个线程的方法总结(精)

     在java中,线程的中断(interrupt)只是改变了线程的中断状态,至于这个中断状态改变后带来的结果,那是无法确定的,有时它更是让停止中的线程继续执行的唯一手段。不但不是让线程停止运行,反而是继续执行线程的...

    Java线程中断的本质深入理解

    Java的中断是一种协作机制。也就是说调用线程对象的interrupt方法并不一定就中断了正在运行的线程,它只是要求线程自己在合适的时机中断自己,本文将详细介绍,需要了解的朋友可以参考下

    Android 通过LooperThread运行线程持续取得系统时间.rar

     我们需要使用Handler类与Message类来处理运行线程,使用Java的Calendar与Thread类来取得系统时间,在编写代码时别忘了引入android.os.Handler;android.os.Message;java.util.Calendar;等相关类;  在编写时,我们...

    浅析java线程中断的办法

    这个方法能中断正在运行的线程,但是已经不推荐使用了,在将来的版本或许弃用,因为强行中断运行中的线程,是不安全的。 void thread.interrupt() 如果正在运行wait(),sleep(),join()这三个方法阻塞了线程,那么...

    Java中断线程的方法

    Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!  现在,如果你要安全有效地终止一个线程,应该采用以下这些方法: ...

    多线程实验

    编写一个Java应用程序,在主线程中再创建2个线程,要求线程经历4种状态:新建、运行、中断和死亡

    实验多线程

    (1) 掌握线程与多线程的基本概念。 (2) 掌握创建线程的两种基本方法。 (3) 掌握Thread类得常用方法,如start(),run(),stop(),sleep()等的使用。 (4) 掌握编写同步代码的方法。

    interrupt()和线程终止方式_动力节点Java学院整理

    线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态位,即设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身。线程会不时地检测这个中断标示位,以...

    线程生命周期.pdf

    以图表形式详细列出java线程生命周期,创建线程,线程就绪,线程阻塞,线程中断,线程唤醒,线程运行之间的关系

    JAVA2核心技术(中文的PDF).part3.rar

    1.3.2 可运行线程 13 1.3.3 被阻塞线程 14 1.3.4 死线程 15 1.4 线程属性 15 1.4.1 线程优先级 15 1.4.2 守护线程 16 1.4.3 线程组 16 1.4.4 未捕获异常处理器 18 1.5 同步 19 1.5.1 竞争条件的一个例子 19 1.5.2 ...

    Java 7并发编程实战手册

    全书通过60多个简单而非常有效的实例,帮助读者快速掌握Java 7多线程应用程序的开发技术。学习完本书,你可以将这些开发技术直接应用到自己的应用程序中。 《Java 7并发编程实战手册》适合具有一定Java编程基础的...

    Java的线程机制

    这种单线程执行方法使系统运行效率低,而且,由于必须依*中断来处理输入/输出。所以,当出现频繁输入/输出或者有优先级较低的中断请求时,实时性就变得很差。多线程系统可以避免这个缺点。所谓

    华为java培训讲义

    虚拟机判定内存不够的时候会中断代码的运行,这时候gc才进行垃圾回收 缺点:不能够精确的去回收内存 java.lang.System.gc(); 建议回收内存,但系统不一定回应,他会先去看内存是否够用,够用则不予理睬,不够用才...

    Java并发编程(学习笔记).xmind

    (4)用户界面具备更短的响应时间:现代GUI框架中大都使用一个事件分发线程(类似于中断响应函数)来替代主事件循环,当用户界面用有事件发生时,在事件线程中将调用对应的事件处理函数(类似于中断处理函数) ...

    java初学者必看

    1.5.2 Java运行环境 1.6 Java技术体系 1.7 Java虚拟机 1.7.1 虚拟机数据类型 1.7.2 Java虚拟机的生命周期 1.7.3 Java虚拟机的体系结构 1.8 垃圾收集器 1.9 本章习题 第2章 Java开发环境 2.1 J2SE的下载和...

    一文带你读懂线程的启动和终止,

    在运行线程之前首先要构造一个线程对象,java.Lang.Thread中为我们提供了一个用于创建线程时的初始化方法。主要对线程中的属性进行初始化 主要的属性 ThreadGroup g:线程组 Runnable target:可以调用run方法的对象...

Global site tag (gtag.js) - Google Analytics