Java Thread.interrupt 害人! 中断JAVA线程(zz)
http://www.blogjava.net/jinfeng_wang/archive/2012/04/22/196477.html#376322
——————————————————————————————————————————————————————————
| 程序是很简易的。然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的、难以发现的错误。 在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程。 背景 中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。线程是死亡、还是等待新的任务或 首先,忘掉Thread.stop方法。虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的JAVA版本中,它将不复存在。 |
|
|
一些轻率的家伙可能被另一种方法Thread.interrupt所迷惑。尽管,其名称似乎在暗示着什么,然而,这种方法并不会中断一个正在运行 class Example1 extends Thread {
如果你运行了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... 真正地中断一个线程 中断线程最好的,最受推荐的方式是,使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。线程必须周期性 Listing B 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..." ); } } Starting thread... Thread is running... Thread is running... Thread is running... Asking thread to stop... Thread exiting under request... Stopping application... 虽然该方法要求一些编码,但并不难实现。同时,它给予线程机会进行必要的清理工作,这在任何一个多线程应用程序中都是绝对需要的。请确认将共享变量 到目前为止一切顺利!但是,当线程等待某些事件发生而被阻塞,又会发生什么?当然,如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下 他们都可能永久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使用某种机制使得线程更早地退出被阻塞的状态。 很不幸运,不存在这样一种机制对所有的情况都适用,但是,根据情况不同却可以使用特定的技术。在下面的环节,我将解答一下最普遍的例子。 使用Thread.interrupt()中断线程 正如Listing A中所描述的,Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞 因此,如果线程被上述几种方法阻塞,正确的停止线程方式是设置共享变量,并调用interrupt()(注意变量应该先设置)。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最后线程都将检查共享变量然后再停止。Listing C这个示例描述了该技术。 Listing C 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操作 如果你正使用通道(channels)(这是在Java 1.4中引入的新的I/O API),那么被阻塞的线程将收到一个 但是,你可能正使用Java1.0之前就存在的传统的I/O,而且要求更多的工作。既然这样,Thread.interrupt()将不起作用,因为线程 Listing D 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操作阻塞,该 唯一要说明的是,必须存在socket的引用(reference),只有这样close()方法才能被调用。这意味着socket对象必须被共享。Listing E描述了这一情形。运行逻辑和以前的示例是相同的。 Listing E Starting thread... Waiting for connection... Asking thread to stop... accept() failed or interrupted... Thread exiting under request... Stopping application... 多线程是一个强大的工具,然而它正呈现出一系列难题。其中之一是如何中断一个正在运行的线程。如果恰当地实现,使用上述技术中断线程将比使用Java平台上已经提供的内嵌操作更为简单。 |
|
============================================
Writing multithreaded programs in Java, with its built-in support for
threads, is fairly straightforward. However, multithreading presents a
whole set of new challenges to the programmer that, if not correctly
addressed, can lead to unexpected behavior and subtle, hard-to-find
errors. In this article, we address one of those challenges: how to
interrupt a running thread.
Background
Interrupting a thread means stopping what it is doing before it has
completed its task, effectively aborting its current operation. Whether
the thread dies, waits for new tasks, or goes on to the next step
depends on the application.
Although it may seem simple at first, you must take some precautions in
order to achieve the desired result. There are some caveats you must be
aware of as well.
First of all, forget the Thread.stop method. Although it indeed stops a running thread, the method is unsafe and was deprecated, which means it may not be available in future versions of the Java.
Another method that can be confusing for the unadvised is Thread.interrupt. Despite what its name may imply, the method does not interrupt a running thread (more on this later), as Listing A demonstrates. It creates a thread and tries to stop it using Thread.interrupt. The calls to Thread.sleep() give plenty of time for the thread initialization and termination. The thread itself does not do anything useful.
If you run the code in Listing A, you should see something like this on your console:
Starting thread...
Thread is running...
Thread is running...
Thread is running...
Interrupting thread...
Thread is running...
Thread is running...
Thread is running...
Stopping application...
Even after Thread.interrupt() is called, the thread continues to run for a while.
Really interrupting a thread
The best, recommended way to interrupt a thread is to use a shared
variable to signal that it must stop what it is doing. The thread must
check the variable periodically, especially during lengthy operations,
and terminate its task in an orderly manner. Listing B demonstrates this technique.
Running the code in Listing B will generate output like this (notice how the thread exits in an orderly fashion):
Starting thread...
Thread is running...
Thread is running...
Thread is running...
Asking thread to stop...
Thread exiting under request...
Stopping application...
Although this method requires some coding, it is not difficult to
implement and give the thread the opportunity to do any cleanup needed,
which is an absolute requirement for any multithreaded application. Just
be sure to declare the shared variable as volatile or enclose any access to it into synchronized blocks/methods.
So far, so good! But what happens if the thread is blocked waiting for
some event? Of course, if the thread is blocked, it can't check the
shared variable and can't stop. There are plenty of situations when that
may occur, such as calling Object.wait(), ServerSocket.accept(), and DatagramSocket.receive(), to name a few.
They all can block the thread forever. Even if a timeout is employed, it
may not be feasible or desirable to wait until the timeout expires, so a
mechanism to prematurely exit the blocked state must be used.
Unfortunately there is no such mechanism that works for all cases, but
the particular technique to use depends on each situation. In the
following sections, I'll give solutions for the most common cases.
Interrupting a thread with Thread.interrupt()
As demonstrated in Listing A, the method Thread.interrupt()
does not interrupt a running thread. What the method actually does is
to throw an interrupt if the thread is blocked, so that it exits the
blocked state. More precisely, if the thread is blocked at one of the
methods Object.wait, Thread.join, or Thread.sleep, it receives an InterruptedException, thus terminating the blocking method prematurely.
So, if a thread blocks in one of the aforementioned methods, the correct
way to stop it is to set the shared variable and then call the interrupt() method on it (notice that it is important to set the variable first). If the thread is not blocked, calling interrupt()
will not hurt; otherwise, the thread will get an exception (the thread
must be prepared to handle this condition) and escape the blocked state.
In either case, eventually the thread will test the shared variable and
stop. Listing C is a simple example that demonstrates this technique.
As soon as Thread.interrupt() is called in Listing C,
the thread gets an exception so that it escapes the blocked state and
determines that it should stop. Running this code produces output like
this:
Starting thread...
Thread running...
Thread running...
Thread running...
Asking thread to stop...
Thread interrupted...
Thread exiting under request...
Stopping application...
Interrupting an I/O operation
But what happens if the thread is blocked on an I/O operation? I/O can
block a thread for a considerable amount of time, particularly if
network communication is involved. For example, a server may be waiting
for a request, or a network application may be waiting for an answer
from a remote host.
If you're using channels, available with the new I/O API introduced in Java 1.4, the blocked thread will get a ClosedByInterruptException exception. If that is the case, the logic is the same as that used in the third example—only the exception is different.
But you might be using the traditional I/O available since Java 1.0,
since the new I/O is so recent and requires more work. In this case, Thread.interrupt() doesn't help, since the thread will not exit the blocked state. Listing D demonstrates that behavior. Although the interrupt() method is called, the thread does not exit the blocked state.
Fortunately, the Java Platform provides a solution for that case by calling the close()
method of the socket the thread is blocked in. In this case, if the
thread is blocked in an I/O operation, the thread will get a SocketException exception, much like the interrupt() method causes an InterruptedException to be thrown.
The only caveat is that a reference to the socket must be available so that its close() method can be called. That means the socket object must also be shared. Listing E demonstrates this case. The logic is the same as in the examples presented so far.
And here's the sample output you can expect from running Listing E:
Starting thread...
Waiting for connection...
Asking thread to stop...
accept() failed or interrupted...
Thread exiting under request...
Stopping application...
Multithreading is a powerful tool, but it presents its own set of
challenges. One of these is how to interrupt a running thread. If
properly implemented, these techniques make interrupting a thread no
more difficult than using the built-in operations already provided by
the Java Platform.
Java Thread.interrupt 害人! 中断JAVA线程(zz)的更多相关文章
- Java Thread.interrupt interrupted
Java Thread.interrupt @(Base)[JDK, 线程, interrupt] 原文地址,转载请注明 下面这个场景你可能很熟悉,我们调用Thread.sleep(),conditi ...
- Java Thread系列(二)线程状态
Java Thread系列(二)线程状态 一.线程的五种状态 新建状态(New):新创建了一个线程对象,尚未启动. 就绪状态(Runnable):也叫可运行状态.线程对象创建后,其他线程调用了该对象的 ...
- Java Thread系列(四)线程通信
Java Thread系列(四)线程通信 一.传统通信 public static void main(String[] args) { //volatile实现两个线程间数据可见性 private ...
- Java Thread系列(三)线程安全
Java Thread系列(三)线程安全 一.什么是线程安全 线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的. 线程安全来 ...
- Java Thread系列(一)线程创建
Java Thread系列(一)线程创建 Java 中创建线程主要有三种方式:继承 Thread.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实 ...
- Java Thread interrupt
现有线程对象threadA,调用threadA.interrupt(),则threadA中interrupted状态会被置成false,很多线程中都是通过isInterrupted()方法来检测线程是 ...
- JNI-从jvm源码分析Thread.interrupt的系统级别线程打断原理
前言 在java编程中,我们经常会调用Thread.sleep()方法使得线程停止运行一段时间,而Thread类中也提供了interrupt方法供我们去主动打断一个线程.那么线程挂起和打断的本质究竟是 ...
- Java Thread.join()详解--父线程等待子线程结束后再结束
目录(?)[+] 阅读目录 一.使用方式. 二.为什么要用join()方法 三.join方法的作用 join 四.用实例来理解 打印结果: 打印结果: 五.从源码看join()方法 join是Th ...
- java开发两年,这些线程知识你都不知道,你怎么涨薪?
前言 什么是线程:程序中负责执行的哪个东东就叫做线程(执行路线,进程内部的执行序列),或者说是进程的子任务. Java中实现多线程有几种方法 继承Thread类: 实现Runnable接口: 实现Ca ...
随机推荐
- mysql中bigint在php中表示
http://bbs.csdn.net/topics/340266753 http://www.percona.com/blog/2008/01/10/php-vs-bigint-vs-float-c ...
- Asterisk服务安装配置和启动
Asterisk服务安装配置和启动 2014年11月4日 11:36 注意: 更新源的重要性 源的地址: http://fffo.blog.163.com/blog/static/2119130682 ...
- IOS基础框架
GameKit 为游戏提供网络功能:点对点互联和游戏中的语音交流 AddressBook 提供访问用户联系人信息的功能 AddressBookUI 提供一个用户界面,用于显示存储在地址簿中的联系人信息 ...
- 安卓自动化测试工具MonkeyRunner之使用ID进行参数化,以及List选择某项和弹出框点击确定的写法
一.List选择某项的操作步骤: 1.通过父结点得出列表各子项 2.将选择项的文本与列表中的子项进行比较 3.计算出选择项的坐标位置 截取实例: from com.android.monkeyrunn ...
- Error Curves(2010成都现场赛题)
F - Error Curves Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu Descript ...
- TCP/IP详解学习笔记(9)-TCP协议概述
终于看到了TCP协议,这是TCP/IP详解里面最重要也是最精彩的部分,要花大力气来读.前面的TFTP和BOOTP都是一些简单的协议,就不写笔记了,写起来也没啥东西. TCP和UDP处在同一层---运输 ...
- JS动态呈现还可以输入字数
现在觉得当我们使用js或者jquery来呈现一个动态效果时,主要还是要想清楚它的思想.它的原理.而动态呈现输入字数,其实就是给它设置一个最大输入字数,然后获取已输入的字数,自然想做什么都可以. < ...
- Ios 程序封装,安装流程
转:http://www.myexception.cn/operating-system/1436560.html Ios 程序打包,安装流程 一.发布测试,是指将你的程序给 * 你的测试人员,因 ...
- button捕捉回车键
为了给一个页面设置回车默认触发的按钮功能,我浏览了IE上的诸多方法,有的言不达意,有的读不懂,后来把高手的一段代码改造后,形成了一段代码,使这个问题的解决变得非常简章,有兴趣的朋友不妨一试.<s ...
- 【转】C++ 内存分配(new,operator new)详解
本文主要讲述C++ new运算符和operator new, placement new之间的种种关联,new的底层实现,以及operator new的重载和一些在内存池,STL中的应用. 一 new ...