|
![]() |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
由于可能导致非常行为的产生,多线程技术显然对于开发人员来说提出了一系列新的挑战。本文,我们将就这些挑战之一:如何中断一个正在运行的线程展开讨论。 在Java中通过其内建的线程支持,编写多线程的程序还是相称简朴的。然而,采用多线程技术将对程序开发人员提出了一些列的挑战,假如没有得到准确的处理,可能会导致非常行为的产生,以及难以发现的差错。本文,我们将就这些挑战之一:如何中断一个正在运行的线程展开讨论。 背景 中断一个线程意味着在完成其任务以前,停止线程正在进行的工作,即有效的中止当前操作。线程中断后是等待新的任务还是继承进行下一步操作将取决于应用程序。 尽管在最初看起来比较简朴,你还是需要预先采取一些措施以求获得理想的结果。这里就你必须注重的问题提出了一些建议: 首先,不要使用Thread.stop方式。尽管它的确可以中止一个正在运行的线程,但这样的方式并不安全,并遭到了开发人员普遍的反对。这也可能意味着在未来的Java版本中它可能不会出现。 另一种并不建议的方式是Thread.interrupt。有人可能会将其与上文提到的方式相混淆。不论它的名字表示什么,这种方式事实上并没有立刻中断一个正在运行的线程(后来也不会),如列表A所示。它创建了一个线程,并且尝试使用Thread.interrupt来停止此线程。对Thread.sleep()的调用提供了充裕的时间来进行线程的初始化和结束。线程本身并没有做任何有用的事情。 假如运行列表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.interrupt()之后,线程还是运行了一段时间。 真正的中断一个线程 中断一个线程的最好的推荐方式是使用一个共享变量来指示线程必须中止目前所做的工作。线程必须周期性的对变量进行检查,尤其在处理较长的操作的时候,然后通过有序的方法中止线程任务。列表B的代码给出了此技术的详细实现: 运行列表B中的代码将会产生如下输出(注重线程在前一种方式中是如何退出的): Starting thread... Thread is running... Thread is running... Thread is running... Asking thread to stop... Thread exiting under request... Stopping application... 尽管这样的方式需要编写一定量代码,但这并不会给执行这些线程以及根据需要对线程进行清除带来多大麻烦,而尤其是清除线程对于任何一个多线程的应用程序来说都是绝对必需的。只需要确保已经对共享变量声明为可变,或者将任何对其的访问封装在同步代码块或方式里面。 到现在为止,一切都很顺利。但假如线程被封锁以等待一些事件,那么将会发生些什么?当然,假如线程被封锁,它将不能对共享变量进行检查,从而无法停止。有很多时候会发生这样的情况,诸如对Object.wait()、ServerSocket.accept()以及DatagramSocket.receive()瞪函数进行调用的时候。 这些函数都能够将线程永远的封锁起来。即使采用了超时机制,或许也不会可行,或者让人无法忍受线程一直运行直到到达超时状态。所以必须采用某种机制以使线程提早的退出封锁状态。 不幸的是,这里还没有这样的机制能够适用于所有的情况。但可以根据详细的情况来使用一些特定的技巧。在如下的部分,我将给出对于绝大部分的常见情况所采取的解决方案。 通过Thread.interrupt()中断一个线程 如列表A所示,采用Thread.interrupt()方式并没有中断一个正在运行的线程。此方式事实上做的只是假如线程被封锁则抛出一个中断信号,由此线程退出了封锁状态。更为精确的讲,假如线程被封锁在方式Object.wait、Thread.join或是Thread.sleep,它将接收一个InterruptedException,从而提前终结封锁方式。 因此,假如一个线程被封锁在上述方式中的任意一个,停止它的准确方式是设置共享变量,并对其调用interrupt()方式(注重首先设置变量异常重要)。假如线程没有被锁定,调用interrupt()则无关紧要,否则,线程将会得到一个非常(线程本身必须预备好处理这种情况)然后退出锁定状态。在任何一种情况中,最终线程都将会检测共享变量并终止。列表C的简朴范例程序表明了这一技术的运用。 一旦Thread.interrupt()在列表C代码中得到调用,线程将获得一个非常,于是它退出了封锁状态并决定它应当停止。运行这些代码将输出一下结果: 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可以在一段可观的时间里保持对一个线程的封锁,尤其涉及网络通信的时候。比如,一个服务器可能会等待用户哀求,或者一个网络应用程序会等待远程主机的响应。 假如你正在使用通道――在Java 1.4中可以获得的新的I/O API――封锁的线程将会得到一个ClosedByInterruptException非常。假如是这种情况,处理的逻辑方式与在第三个例子中所使用的一样――不同的仅仅是产生的非常有所区别。 但是,由于新的I/O最近才发布并且还有待进一步研究,你也可能还在使用Java 1.0以来一直提供的传统的I/O。这种情况下,使用Thread.interrupt()不会产生任何帮助,原因是线程将不会退出封锁状态。列表D中的代码显示了这一过程。尽管调用了interrupt()方式,线程还是没有退出封锁状态。 值得庆幸的是,Java Platform提供了在这种情况下的解决方案:通过调用锁定线程的socket的close()方式。这样的情况下,假如线程是在进行I/O操作时被锁定,线程将得到一个SocketException非常,这异常类似于interrupt()方式引发了InterruptedException非常的情况。 唯一需要提醒的地方是对socket的引用必须可用,这样的话close()方式才能被调用。这也意味着socket对象也必须被共享。列表E显示了这种情况。处理的逻辑过程与以前给出的范例一样。 运行列表E中代码将会得到如下预期结果: Starting thread... Waiting for connection... Asking thread to stop... accept() failed or interrupted... Thread exiting under request... Stopping application... 多线程是功能异常强盛的工具,但也给自身的处理带来了一些列挑战。其中之一便是如何中断一个正在运行的线程。假如处理得当,使用这些技术中断线程的难度将不会大于使用Java Platform提供的内建操作完成同样的任务。 列表A:通过Thread.interrupt()中断线程 class Example1 extends Thread { 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 ( true ) { System.out.println( "Thread is running..." ); long time = System.currentTimeMillis(); while ( System.currentTimeMillis()-time < 1000 ) { } } } } 列表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..." ); } } 列表C:通过Thread.interrupt()退出封锁状态 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..." ); } } 列表D:通过Thread.interrupt()中断I/O操作 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..." ); } } } } 列表E:I/O操作失败 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..." ); } } 返回类别: 教程 上一教程: 学习Java的笔记(4) 下一教程: 现成的class实现crypt算法 您可以阅读与"中断Java线程"相关的教程: · java多线程,什么时候让我跨过你高高的门槛 · java 线程安全 · JAVA多线程编程详解 · Java游戏起步:(一)线程与线程池 · Java开发中的线程安全选择与Swing[Z] |
![]() ![]() |
快精灵印艺坊 版权所有 |
首页![]() ![]() ![]() ![]() ![]() ![]() ![]() |