上一篇文章我们了解过了java有关线程的基本概念,有线程的属性,线程可能处于的状态,还有线程的两种创建的方式,最后还说了一个关键字synchronized,解决了高并发导致数据内容不一致问题,本篇文章就介绍线程的中断机制。

     首先我们需要知道,java中的每个对象都是有内部对象锁的,其实每个java对象不止包含一个内部对象锁,还包含了一个等待队列和一个条件队列。

public synchronized void showName(){
    ************
}

这样的一个被synchronized关键字修饰的方法,如果已经有线程获得了该对象的锁,再有线程过来就会被阻塞并丢入等待队列中。

private int count;
public synchronized void showName(){
    if(count==0){
        wait();
    }
}

public synchronized void setName(){
    if(count==0){
        notifyAll();
    }
}

而在上述的代码段中,出现了两个方法:wait和notifyAll。这两个方法是成对出现的,wait主要作用是将当前线程阻塞并且置入条件队列上,notifyAll主要用于解放条件队列上的所有线程,使他们可以再次竞争处理机的调度以便运行。

     小结一下,以上就比较了等待队列和条件队列的作用和区别。等待队列往往是因为想要申请的锁已经被别的线程占有了,需要置入等待队列等待占有锁的线程释放锁,然后接受处理机调度,被选中后方能获得锁并运行。而条件队列却是一个已经获得锁的线程在执行过程中发现自己继续运行的条件不满足(无法获得某些需要的资源),程序无法继续执行下去了,于是调用wait方法阻塞自己并释放外部对象锁,置入条件队列。

     一旦占有某类资源的线程释放该资源之后,调用notifyAll方法释放所有在条件队列上等待的线程,使他们重新接受处理机的挑选。如果被处理机选中运行,就会从条件队列出队,占有对象锁,开始运行。需要注意的是:wait和notifyAll方法只能在synchronized修饰的代码块中调用,否则就会抛出异常。其实原因也很简单,wait必须指定将当前的线程挂在什么对象的条件队列上,notifAll必须被指定释放什么对象上的所有条件队列中的线程。synchronized关键字是针对某个对象加锁的,在其代码块中调用上述两种方法就默认操作被锁住的对象的条件队列。



一、如何中断

     接下来我们看看线程的中断,有人会问:每个线程执行自己的程序,直到程序的最后一条代码,执行完成之后就会自动的死亡,为什么要使用中断机制来主动的让他死亡呢?其实在我们的程序中往往需要在程序执行的过程中显式的就是线程的运行。比如:有些线程永远不会执行结束,比如你打开浏览器访问网站,如果没有中断线程机制,你永远都不会等到线程运行结束的那一刻。只能通过显式的中断来结束一个线程的运行。

     Thread类中定义了如下几个关于中断的方法:

public boolean isInterrupted()
public void interrupt()
public static boolean interrupted()

三者方法名类似,但是却具有完全不同的操作。isInterrupted() 方法其实就是判断当前线程是否被中断,interrupt() 方法表示将线程的中断状态置为true,interrupted() 方法是一个静态的方法,测试当前线程的中断状态是否为true,和第一种方法功能一样,但是这个方法有一个额外的操作:会将调用此方法的线程的中断状态位置为false。就是顺便将中断位置为false。



二、线程的不同的状态对中断的反应

     我们知道线程的状态主要有,New,Runnable,Blocked,waiting,Terminated。下面我们看看每种状态下的线程对于中断的应对是怎么样的。

     首先是New状态,New状态下的线程并没有处于运行状态,这个状态下,中断操作对该线程没有任何影响。中断标志位也不会被置为true。其实可以理解的,一个都没有机会运行的线程,本来就是处于类似于中断的状态下。这种状态和Terminated状态下的线程对于中断的反应是一样的。

     下面我们看看Runnable状态下的线程是怎样的反应。一个正在运行的线程,如果调用了interrupt方法,只会将此线程的中断表示为置为true,一旦该线程在某个阶段检测自己的中断表示位,发现如果是true就会中断线程。但是在没有自我检测的期间,线程是可以正常运行的。

public class Test_thread extends Thread{
    public void run(){
        while(true) {

        }
    }
}

public class Test_Class {
    public static void main(String[] args){
        Thread thread = new Test_thread();
        thread.start();
        thread.interrupt();
        try{
            Thread.sleep(1000);
        } catch (InterruptedException e){

        };

        System.out.println(thread.isInterrupted());
    }
}
/*输出:true*/

如上述的程序运行结果所示,一个将正在运行的线程interrupt,虽然标示位已经被更改,但是线程不会因此被中断。



     接下来看看Blocked状态下线程应对中断的反应。本篇文章的开头已经说过了,Bloked状态是由于申请某个对象的锁失败之后被放置在了该对象的等待队列上,这个队列上的线程都是Blocked状态的。在这种状态下,调用interrupt() 方法,一样的只会将该线程的中断标志位置为true但是不会导致该线程退出等待队列。

public class Test_Class {

    private static Object count = new Object();
    public static void main(String[] args){
        try {
            show();
        }catch (InterruptedException e){}
    }

    public static void show() throws InterruptedException{
        synchronized (count){
            Thread thread = new myThread();
            thread.start();
            thread.interrupt();
            System.out.println(thread.isInterrupted());
            System.out.println(thread.getState());

            thread.join();
        }
    }
    public static class myThread extends Thread{
        public void run(){
            synchronized (count){
                while(!Thread.currentThread().isInterrupted()){

                }
                System.out.println(this.toString());
            }
        }
    }
}
/*
输出结果:
true
BLOCKED
*/

我们在main函数中调用show方法(这是一个线程),获取count的锁,在show方法内部创建一个线程,start之后执行run方法时没有能够获得count的锁,接着中断该线程,于是被阻塞在等待队列中。从输出的结果可以看出,一个状态是Blocked的线程在被中断之后,除了中断状态位被修改之后,其余没有什么变化。



          最后,我们看线程的waiting状态,一个处于waiting状态的线程,执行方法interrupt,会导致抛出Inerruption异常,即不允许一个处于waiting状态的线程被中断。但是,有一点是:此异常被抛出之后,会清空中断标志位。

public class Test_thread extends Thread{
    public void run(){
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            System.out.println(0);
        }
    }
}

public class Test_Class {
    public static void main(String[] args){
        Thread thread = new Test_thread();
        thread.start();

        try{
            Thread.sleep(100);
        }catch (InterruptedException e){
            System.out.println(1);
        }
        thread.interrupt();
        try {
            thread.join();
        }catch(InterruptedException e){
            System.out.println(3);
        }
    }
}

启动新线程,调用sleep方法使该线程处于waiting状态,与此同时,主线程调用子线程的interrupt方法,中断该线程,于是处于waiting状态的线程抛出异常,被捕获之后输出0;



          本篇文章结束,大家需要知道的就是在线程处于不同的状态下,遇到中断的处理方式是不一样的,对于是否就行处理其实还是取决与我们程序员写的代码。文章依然是自己阅读别人博客和自己总结实践得来,如果有错误,望大家指出来。感谢!

java 线程中断机制的更多相关文章

  1. Java线程中断机制-如何中断线程

    介绍: 对于线程一共分为五个状态:新建状态,就绪状态,阻塞状态,运行状态,死亡状态,有时候把阻塞状态又分为同步阻塞和等待阻塞. 有时想让主线程启动的一个子线程结束运行,我们就需要让这个子线程中断,不再 ...

  2. Java基础知识强化16:深入分析Java线程中断机制

    1.Thread.interrupt真的能中断线程吗?       在平时的开发过程中,相信都会使用到多线程,在使用多线程时,大家也会遇到各种各样的问题,今天我们就来说说一个多线程的问题——线程中断. ...

  3. Java 线程的中断机制

    今天我们聊聊 Java 线程的中断机制. 线程中断机制提供了一种方法,用于将线程从阻塞等待中唤醒,并作出相应的“受控中断”处理. synchronized (lock) { try { while ( ...

  4. 【转载】 Java线程面试题 Top 50

    Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...

  5. Java线程面试题 Top 50 (转载)

    转载自:http://www.cnblogs.com/dolphin0520/p/3958019.html 原文链接:http://www.importnew.com/12773.html   本文由 ...

  6. 50 道 Java 线程面试题(转载自牛客网)

    下面是 Java 线程相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理 ...

  7. Java线程面试题 Top 50

    转自:http://www.importnew.com/12773.html 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java ...

  8. java线程中断和终止线程运行

    ava中启动一个线程很容易,通常情况下我们都是等到任务运行结束后让线程自行停止.但有时需要在任务正在运行时取消他们,使得线程快速结束.对此Java并没有提供任何机制.但是我们可以通过Java提供的线程 ...

  9. 【多线程】Java线程面试题 Top 50(转载)

    Java线程面试题 Top 50 原文链接:http://www.importnew.com/12773.html   本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎 ...

随机推荐

  1. Angular - - ngReadonly、ngSelected、ngDisabled

    ngReadonly 该指令将input,textarea等文本输入设置为只读. HTML规范不允许浏览器保存类似readonly的布尔值属性.如果我们将一个Angular的插入值表达式转换为这样的属 ...

  2. 勘误《iOS网络高级编程:iPhone和iPad的企业应用开发》

    VII页 , 倒数第二行, “其他” 应为 “其它” X页, 源代码有错误,说是有19章,实际一共13章 XI页,勘误表的链接也是错误的  .是该书的<Beginning ASP.NET 4.5 ...

  3. 【HDU 5808】 Price List Strike Back (整体二分+动态规划)

    Price List Strike Back There are nn shops numbered with successive integers from 11 to nn in Bytelan ...

  4. 解决Apache的错误日志巨大的问题以及关闭Apache web日志记录

    调整错误日志的级别 这几天 apache错误日志巨大 莫名其妙的30G  而且 很多都是那种页面不存在的  网站太多了  死链接相应的也很多于是把错误警告调低了 因为写日志会给系统带来很大的损耗.关闭 ...

  5. Struts2框架学习(三) 数据处理

    Struts2框架学习(三) 数据处理 Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:Value ...

  6. js模块化开发——前端模块化

    在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可:如今CPU.浏览器性能得到了极大的提升,很多页面逻辑迁移到了客 户端(表单验证等),随着web2.0时代的到来,Ajax技术 ...

  7. HDU5882

    Balanced Game Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tot ...

  8. EmitMapper 和TinyMapper 两者简单对比

    EmitMapper 和TinyMapper 两者的性能都是很高,相比autoMapper 速度不知道快了多少倍,因为使用的最多EmitMapper,所在业余时间做了一下测试对比. 测试数据:10万条 ...

  9. Lottie简介(翻译)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6364634.html Lottie简介(翻译) 新的向本地ap ...

  10. 应对linux下的闰秒

    文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/6339470.html  转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...