zoukankan      html  css  js  c++  java
  • 简单理解线程--阻塞,interrupt

    什么是线程

      线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本不拥有资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进行所拥有的所有资源。

    阻塞和非阻塞

      阻塞和非阻塞是形容多个线程之间的相互影响的(前提是多线程而不是一个),一个线程占用了临界区资源,那么其他线程必须在临界区外等待,阻塞是操作系统层面挂起,上下文切换了,所以性能不高。如果一个线程一直占用不释放资源,那么其他需要该临界区资源的线程都必须一直等待。非阻塞就是运行多个线程同时进入临界区,只要保证不把数据修改坏就行。

    阻塞的情况分三种:

    • 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    • 其他阻塞:运行的线程执行sleep()或join()方法时,或者发出I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时,join()等待线程终止或者超时,或者I/O处理完毕时,线程重新转入就绪状态。
     1 /*   
     2 
     3  * 如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下会发生,例如调用  
     4  * Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,他们都可能永  
     5  * 久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使  
     6  * 用某种机制使得线程更早地退出被阻塞的状态。很不幸运,不存在这样一种机制对所有的情况  
     7  * 都适用,但是,根据情况不同却可以使用特定的技术。使用Thread.interrupt()中断线程  
     8  * Thread.interrupt()方法不会中断一个正在运行的线程。这一方法  
     9  * 实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更  
    10  * 确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,  
    11  * 它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。因此,  
    12  * 如果线程被上述几种方法阻塞,正确的停止线程方式是设置共享变量,并调用interrupt()(注  
    13  * 意变量应该先设置)。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就  
    14  * 将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最  
    15  * 后线程都将检查共享变量然后再停止。下面示例描述了该技术。  
    16  * */
    17 class Example extends Thread {
    18 
    19     volatile boolean stop = false;
    20 
    21     public static void main(String args[]) throws Exception {
    22         Example thread = new Example();
    23 
    24         System.out.println("Starting thread...");
    25         thread.start();
    26         
    27         System.out.println("sleep 3S......");
    28         Thread.sleep(3000);
    29 
    30         System.out.println("Asking thread to stop...");
    31 
    32         /*
    33          * 如果线程阻塞,将不会检查此变量,调用interrupt之后,线程就可以尽早的终结被阻塞状态,能够检查这一变量。
    34          */
    35         System.out.println("stop==true......");
    36         thread.stop = true;
    37         
    38         
    39         /*
    40          * 这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态
    41          */
    42         System.out.println("interrupt......");
    43         thread.interrupt();
    44         
    45         Thread.sleep(3000);
    46         System.out.println("Stopping application...");
    47         System.exit(0);
    48     }
    49 
    50     public void run() {
    51         while (!stop) {
    52             System.out.println("Thread running...");
    53             try {
    54                 System.out.println("sleep  2S......");
    55                 Thread.sleep(2000);
    56             } catch (InterruptedException e) {
    57                 // 接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态
    58                 System.out.println("Thread interrupted...");
    59             }
    60         }
    61 
    62         System.out.println("Thread exiting under request...");
    63     }
    64 }

    把握几个重点:
    stop变量、run方法中的sleep()、interrupt()、InterruptedException。串接起来就是这个意思:
      当我们在run方法中调用sleep(或其他阻塞线程的方法)时,如果线程阻塞的时间过长,比如10s,那在这10s内,线程阻塞,run方法不被执行,但是如果在这10s内,stop被设置成true,表明要终止这个线程,但是,现在线程是阻塞的,它的run方法不能执行,自然也就不能检查stop,所以线程不能终止,这个时候,我们就可以用interrupt()方法了:我们在thread.stop = true;语句后调用thread.interrupt()方法, 该方法将在线程阻塞时抛出一个中断信号,该信号将被catch语句捕获到,一旦捕获到这个信号,线程就提前终结自己的阻塞状态,这样,它就能够再次运行run方法了,然后检查到stop = true,while循环就不会再被执行,在执行了while后面的清理工作之后,run方法执行完 毕,线程终止。

    http://mp.weixin.qq.com/s/1u95m2EcHFbbJNRv3GJlbQ

  • 相关阅读:
    【云栖社区001-数据结构】如何实现一个高效的单向链表逆序输出(Java版)
    全球疫情爬取及展示
    两个命令配置云服务器web开发环境
    云服务器的两类系统特点整理介绍
    团队介绍和项目简介
    Navicat连接阿里云服务器上MySQL数据库
    Android_bilibili式评论及回复的简单实现
    人月神话阅读笔记02
    每日进度博客_2
    每日进度博客_1
  • 原文地址:https://www.cnblogs.com/shangdongbin/p/7723543.html
Copyright © 2011-2022 走看看