上一篇文章我们了解过了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. iPhone应用中加入评分功能

    NSString *str = [NSString stringWithFormat: @"itms-apps://ax.itunes.apple.com/WebObjects/MZStor ...

  2. 解决Centos 7 下 tomcat字体异常 Font '宋体' is not available to the JVM

    错误提示: SEVERE: Servlet.service() for servlet [example] in context with path [/myproject] threw except ...

  3. C的memcpy和strcpy的区别

    strcpy是拷贝字符串,以\0为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止) strcpy的原型为 char *strcpy(char *dest, const char *src) 而 ...

  4. Java8 Lumbda表达式 初步

    Java8 Lumbda表达式 初步 package com.stono.test; import java.util.function.BinaryOperator; public class Te ...

  5. Spring的 classpath 通配符加载配置文件

    http://www.cnblogs.com/taven/archive/2012/10/24/2737556.html classpath:app-Beans.xml 说明:无通配符,必须完全匹配 ...

  6. Docker,容器,虚拟机和红烧肉

    Docker火了,有多火你自己看看下面的统计数据就知道了 在发布4个月的时间里,下载量就超过50000次,github上收到超过4000个star,涌现了超过100个贡献者,并且有超过150个项目和超 ...

  7. Microsoft IoT Starter Kit 开发初体验-反馈控制与数据存储

    在上一篇文章<Microsoft IoT Starter Kit 开发初体验>中,讲述了微软中国发布的Microsoft IoT Starter Kit所包含的硬件介绍.开发环境搭建.硬件 ...

  8. ECMAScript 6 笔记(四)

    Symbol 1. 概述 ES6引入了一种新的原始数据类型Symbol,表示独一无二的值.它是JavaScript语言的第七种数据类型,前六种是:Undefined.Null.布尔值(Boolean) ...

  9. 面试之MySQL基本命令

    既然要操作数据库就从数据库链接写起,包括建库.建表.增删该查字段及约束,删库,删表的数据,以下主要是对我以往面试的总结,欢迎补充! 一.数据库连接 1.连接本机(p和密码123456之间无空格) my ...

  10. TFS2010升级至TFS2013完全指南

    一.背景:         公司已使用tfs2010很长时间,目前随着公司的发展,项目越来越少,而产品越来越多,采用的开发模式,也逐渐从瀑布式.迭代式转向敏捷开发.为了更好的支持产品研发,决定将tfs ...