`
小野bupt
  • 浏览: 14803 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

有关线程中断和线程阻塞

 
阅读更多

一个线程都要从运行到结束都要经过3个阶段:

1、正在运行

2、准备结束运行

3、结束运行

那么怎么结束这个线程呢?可以通过下面这三个方法结束一个线程。

1、使用stop()方法强制结束线程。

2、使用thread.interrupt()方法发送中断。

3、在Thread对象中设置共享变量,通过在run方法中不断检测该变量的值来决定是否结束。

第一种方法,stop()方法

臭名昭著的stop()停止线程的方法已不提倡使用了,原因是什么呢?当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,并抛出特殊的ThreadDeath()异常。这里的“立即”因为太“立即”了,假如一个线程正在执行:

synchronized void {
 x = 3;
 y = 4;
}
由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整

的残废数据。而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记 线程的stop方法,以后我们再也不要说“停止线程”了。


第二种方法,中断线程。

每个线程都有一个线程中断标志位来标志该线程是否被中断。我们可以通过检测该标志位是否为true来判断该线程是否被中断。调用线程的thread.interrupt()方法,将会设置该线程为中断状态,即设置为true。线程中断后的结果是死亡、还是等待新的任务或是继续运行至下一步,取决于这个程序本身线程会不时地检测这个中断标识位,以判断线程是否应该被中断(中断标识值是否为true)。它并不像stop方法那样会中断一个正在运行的线程。

当我们调用thread.interrupt()方法时,会将thread的中断标志位设为true。通过isInterrupted()方法可以判断标志位是否为true。此后程序是该继续还是结束就取决于程序本身了。

注意如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态),则在线程在检查中断标识时如果发现中断标示为true,则会在这些阻塞方法(sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法)调用处抛出InterruptedException异常,并且在抛出异常后立即将线程的中断标别位清除,即重新设置为false。抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。一个抛出了InterruptedException的线程的状态马上就会被置为非中断状态,如果catch语句没有处理异常,则下一 次循环中isInterrupted()为false,线程会继续执行,可能你N次抛出异常,也无法让线程停止。例如下面例子:

public class ThreadA extends Thread {
   int count=0;
   public void run(){
       System.out.println(getName()+"将要运行...");
       while(!this.isInterrupted()){
           System.out.println(getName()+"运行中"+count++);
           try{
               Thread.sleep(400);
           }catch(InterruptedException e){
               System.out.println(getName()+"从阻塞中退出...");
               System.out.println("this.isInterrupted()="+this.isInterrupted());
           }
       }
       System.out.println(getName()+"已经终止!");
   }
}
因为上例中try在while循环里面,当检测到异常时会执行打印语句,当再次进行while(!this.isInterrupted())判定的时候,请注意,由于此时中断标志位已经被重置为false了,所以while循环会一直继续下去。

public class ThreadA extends Thread {
   int count=0;
   public void run(){
       System.out.println(getName()+"将要运行...");
       while(!this.isInterrupted()){
           System.out.println(getName()+"运行中"+count++);
           try{
               Thread.sleep(400);
           }catch(InterruptedException e){
	       this.interrupt();
               System.out.println(getName()+"从阻塞中退出...");
               System.out.println("this.isInterrupted()="+this.isInterrupted());
           }
       }
       System.out.println(getName()+"已经终止!");
   }
}

比较良好处理方法是:

public void run() {   
    try {   
        /*  
         * 不管循环里是否调用过线程阻塞的方法如sleep、join、wait,这里还是需要加上  
         * !Thread.currentThread().isInterrupted()条件,虽然抛出异常后退出了循环,显  
         * 得用阻塞的情况下是多余的,但如果调用了阻塞方法但没有阻塞时,这样会更安全、更及时。  
         */  
        while (!Thread.currentThread().isInterrupted()&& more work to do) {   
            do more work    
        }   
    } catch (InterruptedException e) {   
        //线程在wait或sleep期间被中断了   
    } finally {   
        //线程结束前做一些清理工作   
    }   
}

注,synchronized在获锁的过程中是不能被中断的,意思是说如果产生了死锁,则不可能被中断(请参考后面的测试例子)。与synchronized功能相似的reentrantLock.lock()方法也是一样,它也不可中断的,即如果发生死锁,那么reentrantLock.lock()方法无法终止,如果调用时被阻塞,则它一直阻塞到它获取到锁为止。但是如果调用带超时的tryLock方法reentrantLock.tryLock(long timeout, TimeUnit unit),那么如果线程在等待时被中断,将抛出一个InterruptedException异常,这是一个非常有用的特性,因为它允许程序打破死锁。你也可以调用reentrantLock.lockInterruptibly()方法,它就相当于一个超时设为无限的tryLock方法。

另外不要在你的底层代码里捕获InterruptedException异常后不处理,会处理不当,如下:

void mySubTask(){   
    ...   
    try{   
        sleep(delay);   
    }catch(InterruptedException e){}//不要这样做   
    ...   
}

如果你不知道抛InterruptedException异常后如何处理,那么你有如下好的建议处理方式:
1、在catch子句中,调用Thread.currentThread.interrupt()来设置中断状态(因为抛出异常后中断标示会被清除),让外界通过判断Thread.currentThread().isInterrupted()标示来决定是否终止线程还是继续下去,应该这样做:

void mySubTask() {   
    ...   
    try {   
        sleep(delay);   
    } catch (InterruptedException e) {   
        Thread.currentThread().interrupted();   
    }   
    ...   
}

2、或者,更好的做法就是,不使用try来捕获这样的异常,让方法直接抛出

void mySubTask() throws InterruptedException {   
    ...   
    sleep(delay);   
    ...   
} 

第三个方法,设置中断信号量。

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

package com.ljq.test;

public class ThreadTest extends Thread{
    //线程中断信号量
    volatile boolean stop=false; 
    
    public static void main(String[] args) throws Exception {
        ThreadTest thread=new ThreadTest();
        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...");  
    }
    
    
    @Override
    public void run() {
        //每隔一秒检测一下中断信号量
        while(!stop){
            System.out.println("Thread is running!");
            long begin=System.currentTimeMillis();
            /**
             * 使用while循环模拟sleep方法,这里不要使用sleep,否则在阻塞时会抛InterruptedException异常而退出循环,
             * 这样while检测stop条件就不会执行,失去了意义。 
             */
            while ((System.currentTimeMillis() - begin < 1000)) {
                
            }   
        }
        System.out.println("Thread exiting under request!");   
    }
}

注意:这里将stop变量定义为volatile类型,防止由于本地缓存产生错误。

参考文章:

http://www.cnblogs.com/linjiqin/archive/2011/04/11/2012695.html

http://blog.csdn.net/oscar999/article/details/1755759



分享到:
评论

相关推荐

    java线程阻塞中断与LockSupport使用介绍

    `LockSupport.park(Object blocker)` 中的`blocker`参数用于记录线程阻塞的原因,主要用于调试和跟踪,不会直接影响线程的阻塞或唤醒行为。 **6. LockSupport是否能响应Thread.interrupt()事件?** `LockSupport....

    唤醒阻塞休眠线程示例

    阻塞和休眠是线程在等待资源或特定事件时的状态。 2. **阻塞状态**:线程在执行过程中可能因为等待I/O操作、锁或其他同步机制而进入阻塞状态。一旦条件满足,线程可以自动恢复执行,例如获得锁后。 3. **休眠状态*...

    Java线程中断示例程序的代码清单.pdf

    在上述的Java线程中断示例程序中,我们看到一个简单的场景,模拟了一个班级中的学生(student线程)和教师(teacher线程)的交互。 首先,`TestThread_interrupt.java`是主程序,它创建了一个`ClassRoom`对象,并...

    java线程中断之interrupt和stop.docx

    ### Java线程中断机制详解:`interrupt`与`stop`方法 #### 一、引言 在Java多线程编程中,线程控制是至关重要的技术之一。有时我们需要在特定条件下停止某个线程的执行,或者中断正在等待的线程。Java提供了多种...

    JAVA100例之实例66 实现对线程的控制,中断、挂起、恢复、停止

    Java通过`Thread.interrupt()`方法提供线程中断机制。当调用一个线程的`interrupt()`方法时,并不会立即停止该线程,而是设置线程的中断状态。线程需要通过检查`InterruptedException`异常来响应中断。例如,当线程...

    Java多线程笔记

    Java多线程笔记是 Java 编程语言中关于多线程编程的笔记,涵盖了线程基础知识、线程优先级、线程状态、守护线程、构造线程、线程中断等多方面的内容。 获取简单 main 程序中的线程 在 Java 中,可以使用 ...

    Android线程结束——合理的结束你想结束的线程

    1. **不要直接调用Thread对象的stop()方法**:这个方法已经被弃用,因为它可能引发不安全的线程中断,导致数据损坏。当一个线程正在执行系统资源密集型操作时,突然停止可能会留下资源泄露和不一致的状态。 2. **...

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

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

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

    线程的状态包括新建、运行、中断和死亡。线程的生命周期始于新建,通过调用start()方法进入就绪状态,然后可能进入运行、阻塞或等待,最后在run()方法执行完毕后死亡。 9.2 Thread的子类创建线程: 创建线程的一种...

    java多线程的讲解和实战

    9. **线程中断**:`interrupt()`方法可以标记线程中断状态,线程可以通过检查`isInterrupted()`或`interrupted()`方法来响应中断请求,从而优雅地停止线程执行。 10. **线程局部变量(ThreadLocal)**:为每个线程...

    C#线程 BeginInvoke和EndInvoke使用方法

    本文将深入探讨C#线程中的BeginInvoke和EndInvoke这两个关键方法的使用。 一、C#线程基础 线程是操作系统调度的基本单位,一个进程至少包含一个线程。在需要执行并发任务或者提升程序性能时,开发者会在同一进程中...

    java中断线程的正确姿势完整示例.rar

    在Java编程中,中断线程是一项重要的任务,特别是在多线程环境下,我们可能需要停止某个线程的执行,以优化程序资源的使用或响应特定的系统需求。本示例将详细探讨Java中断线程的正确方法,以确保线程安全且高效地...

    多线程之间的线程通信

    1. **信号量(Semaphore)**:用于控制对共享资源的访问,当资源可用时,信号量值会减一,当资源不足时,线程会被阻塞,直到信号量值增加到允许访问为止。 2. **锁(Lock)**:包括互斥锁(Mutex)和读写锁(RW-Lock)。...

    linux的中断线程化实现[借鉴].pdf

    在Linux操作系统中,中断线程化是一种将中断处理与用户空间任务解耦合的技术,它允许中断处理程序在后台执行,从而改善系统响应时间和资源管理。2.6.25.8内核版本引入了这一特性,使得中断处理更加灵活且高效。 ...

    Java Socket学习---多线程阻塞

    本教程主要探讨的是如何在Java中使用Socket实现多线程阻塞式通信,这通常涉及到服务器端(EchoServer)和客户端(EchoClient)的设计。在本文中,我们将详细解析`EchoServer.java`、`SocketUtils.java`和`EchoClient...

    Java基本功之中断线程的理解[参考].pdf

    Java中的线程中断是多线程编程中一个重要的概念,主要用来优雅地停止线程的执行。线程中断并不是立即终止线程,而是设置线程的中断状态,并通过特定方式来响应这个中断请求。以下是对Java中断线程的详细解释: 1. *...

    线程的挂起、唤醒和终止

    在实际开发中,我们需要遵循最佳实践,避免使用已过时的线程控制方法,而是采用更安全的同步机制和中断机制,以确保程序的稳定性和可靠性。通过不断学习和实践,我们可以更好地驾驭线程,从而提高软件的性能和用户...

    Java多线程机制和线程之间的协作

    4. 死亡:run()方法执行完毕或者线程被中断或异常结束。 线程的阻塞状态是指线程虽然可运行,但由于某种原因无法执行。比如调用sleep()使线程休眠,等待同步锁,调用wait()进入等待状态,或者等待I/O操作完成。线程...

    Java 实例 - 中断线程源代码+详细指导教程.zip

    本教程的压缩包包含了中断线程的源代码实例和详细指导,旨在帮助开发者深入理解和掌握这一核心概念。以下是关于Java中断线程的一些关键知识点: 1. **线程状态**:在Java中,线程有多种状态,包括新建、可运行、...

Global site tag (gtag.js) - Google Analytics