- 浏览: 468475 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
mrshen:
很棒,在其他大神的博客上理清了思路看懂之后,来lz这里用例子学 ...
RED-BLACK(红黑)树的实现TreeMap源码阅读 -
a939639017:
yanf4j check不下来 ?
Java nio 2.0 AIO -
hellostory:
又是抄来的 - -
mysql分表方案 -
davidluoye:
为什么不说下支持的数据库呢?
模糊查询的优化 -
oliveevilo:
表示没看懂
Synchronized和java.util.concurrent.locks.Lock的区别
背景
中断(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平台上已经提供的内嵌操作更为简单。
发表评论
-
中高级技术人员面试
2012-08-06 14:23 1360struts,spring,hiberate知识点。实际上对于 ... -
关联、聚合、组合的关系
2011-08-19 15:18 1357你和你的心脏之间是co ... -
深入JVM锁机制2-Lock
2011-08-19 11:04 1248分类: JVM 2011-07-28 18:15 92人 ... -
深入JVM锁机制1-synchronized
2011-08-19 11:01 1693分类: JVM 2011-07-28 ... -
CAS ABA问题
2011-08-19 10:55 4666首先要知道什么叫CAS(compare and swap):在 ... -
NIO学习系列:缓冲区内部实现机制
2011-08-17 13:55 993接上一篇NIO学习系列:核心概念及基本读写 ,本 ... -
HTTP协议及报文分析
2011-08-15 21:53 3756一次HTTP操作称为一个 ... -
String、StringBuffer与StringBuilder之间区别
2011-08-15 21:44 1052最近学习到StringBuffer,心中有好些疑问,搜 ... -
Java内存溢出
2011-07-13 11:25 1870内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的 ... -
Java nio 2.0 AIO
2011-07-12 21:26 13206按照《Unix网络编程》 ... -
使用Java NIO编写高性能的服务器
2011-07-12 21:16 1151从JDK 1.4开始,Java的标 ... -
准备问题
2011-07-12 12:06 935你觉得有什么优势 特长 捡干货说你对面试的公司有多了解 怎么看 ... -
NIO学习系列:核心概念及基本读写
2011-07-12 10:20 1125NIO学习系列:缓冲区内部实现机制 http://zh ... -
CAP原理和BASE思想
2011-07-12 10:16 1335分布式领域CAP理论,Co ... -
线程高级---读写锁
2011-07-12 10:15 2109读写锁问题也是比较常见的问题,这是因为现实中充斥着这类问题,而 ... -
Java 中的悲观锁和乐观锁的实现
2011-07-12 10:07 1595锁(locking) 业务逻辑的实现过程中,往往需要保证数 ... -
详细介绍Spring事务管理
2011-07-12 09:47 8509在学习spring事务管理时, ... -
URL与URI区别
2011-07-12 09:46 1212今天在看STRUTS配置的时候,发 ... -
spring原理
2011-07-11 15:57 1013spring原理 spr ... -
Synchronized和java.util.concurrent.locks.Lock的区别
2011-07-11 15:24 5184主要相同点:Lock能完成Synchronized所实现的 ...
相关推荐
Java如何中断一个正在运行的线程 Java中的线程中断是指在某个线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。这种操作可能会使线程死亡、等待新的任务或是继续运行至下一步。中断线程需要注意...
在Java编程中,多线程是并发执行任务的关键机制,但同时也带来了许多挑战,其中之一就是如何安全地中断一个正在运行的线程。本篇文章主要探讨了如何正确地中断线程,避免潜在的问题。 首先,我们要明确一点:Java中...
此命令会返回一个整数值,表示线程的状态,如0表示未启动,1表示正在运行,2表示等待,3表示已结束等。 3. **子程序设计**: - 在“子程序1”中,通常会实现线程的主要功能,比如执行特定任务、处理数据等。子程序...
当一个线程正在执行时,如果发生了一个外部中断,操作系统会通过中断处理程序(ISR)来响应这个中断。在中断处理过程中,操作系统可能会切换到另一个线程,这样即使当前线程因为处理中断而暂停,整个程序仍然能够...
C++11关于thead的应用,利用std::condition std::mutex提供如何中断,停止和继续功能,
中断处理通常需要在非常短的时间内完成,因此需要一个专用的栈空间来保存当前执行的上下文,以保证中断处理的快速和安全。在中断处理完成后,使用中断栈保存的上下文信息来恢复之前的执行状态。 栈在函数调用和多...
对于停止线程的按钮,我们需要一种机制来中断正在运行的线程。由于C#线程不直接支持“停止”操作,我们通常使用取消标志或共享变量来指示线程何时应停止。下面是如何实现这个功能: ```csharp private void btnStop...
synchronized可以修饰方法或代码块,确保同一时间只有一个线程可以执行特定代码。另外,wait()和notify()、notifyAll()方法用于线程间的通信,实现线程的互斥和协作。 四、线程优先级 Java线程有10个优先级,从MIN_...
在本实验中,我们要求学生编写一个 Java 应用程序,在主线程中再创建 2 个线程,要求线程经历 4 种状态:新建、运行、中断和死亡。学生需要使用 Thread 类中的 start() 方法来启动线程,并使用 run() 方法来实现线程...
安全终止线程的一个关键是避免在不适当的时间点中断线程的工作。例如,如果线程正在写入共享数据,突然被终止,那么数据可能处于不一致的状态,导致后续程序出错。因此,我们应该尽量设计线程,使其能够自我检查并...
在许多情况下,我们可以通过一个共享变量(通常是volatile类型的)来控制线程是否应该继续运行。这种方式的优点是线程可以在适当的时间点检查该标志并决定是否退出循环,而不是被强制停止。示例代码如下: ```java ...
当主程序或另一个线程设置这个变量为FALSE,正在运行的线程会检查该变量并终止。然而,这种方法存在几个问题: - 全局变量的访问可能引发竞态条件,导致数据不一致。 - 如果线程在检查全局变量和执行退出操作之间...
在示例中,`poolFlag`是一个计数器,用于记录当前正在运行的线程数。`Interlocked.Increment(ref poolFlag)`会原子地增加`poolFlag`的值,而`Interlocked.Decrement(ref poolFlag)`则会原子地减少`poolFlag`的值。 ...
1. synchronized关键字:可以用于修饰方法或代码块,确保同一时刻只有一个线程可以执行特定的代码。例如: ```java public synchronized void someMethod() { // 这里是线程安全的代码 } ``` 2. volatile关键字:...
Java中断一个线程操作是指在某个线程正在执行任务时,强制其停止当前操作的行为。Java提供了多种方式来中断一个线程,包括interrupt()、isInterrupted()和interrupted()函数。这些函数的使用技巧在实际开发中非常...
在这个“另外一个java多线程下载程序源代码”中,我们可以深入学习如何利用Java的多线程特性来创建一个高效的文件下载应用。 首先,我们了解Java中创建线程的两种主要方式: 1. 继承`Thread`类:自定义一个新的类...
这意味着当一个线程阻塞(如等待I/O操作)时,程序需要决定哪个线程应该获得CPU资源。在单个CPU上,这通常意味着在可运行的线程之间切换。在多核系统中,每个核心可以并发地运行不同线程,进一步提高了并行性。 在...
在 Java 中,线程中断是通过 interrupt 方法来实现的,该方法只是给线程置一个中断标志位,并不会立即停止线程的运行。interrupted 方法可以判断是否被中断,静态方法 interrupted() 则可以判断是否被中断,并清除...
在一个单线程的程序中,任务是按顺序执行的,而多线程则可以并发执行任务,提高了程序的执行效率和用户体验。在Android或Java等平台中,多线程常用于处理耗时操作,如网络请求、数据计算或者复杂的UI更新,避免阻塞...