★ 线程状态

       Java虚拟机将线程运行过程分成四种状态 。 (1) New 新生;(2) Runnable 可运行;(3) Blocked 阻塞;(4) Dead 死亡。

      值得注意的是: 线程的可运行状态并不代表线程一定在运行(runnable != running ) 。 大家都知道:所有现代桌面和服务器操作系统都使用了抢占式的线程调度策略。一旦线程开始执行,并不是总是保持持续运行状态的。当系统分给它的时间片(非常小的运行时间单位)用完以后,不管程序有没有执行完,线程被强制放弃CPU,进入就绪状态,直到下次被调度后开始继续执行。也就是说, Runnable可运行状态的线程处于两种可能的情况下:(1)占用CPU运行中,(2)等待调度的就绪状态。 这里要声明一下:处于等待调度的就绪状态线程和处于阻塞的线程是完全不同的。就绪的线程是因为时间片用完而放弃CPU,其随时都有可能再次获得CPU而运行,这一切取决于分时OS的线程调度策略。

       在很多操作系统的专业术语中,这种因时间片用完而被剥夺CPU的情况我们叫做线程中断 。注意这和我们下面要将得中断线程是两个完全不同的概念。事实上,我们不可能通过应用程序来控制CPU的线程中断,除非我们能够自由调用OS的内核。


★ 中断线程 —— interrupt()

       一个正在运行的线程除了正常的时间片中断之外,能否被其他线程控制?或者说其他线程能否让指定线程放弃CPU或者提前结束运行? 除了线程同步机制之外,还有两种方法:
       (1) Thread.stop(), Thread.suspend(), Thread.resume() 和Runtime.runFinalizersOnExit() 这些终止线程运行的方法 。这些方法已经被废弃,使用它们是极端不安全的。
       (2) Thread.interrupt() 方法是很好的选择。但是使用的时候我们必须好好理解一下它的用处。


Java代码  

java Thread根据线程名字停止 java线程interrupted_Java


1. //无法中断正在运行的线程代码  
2. class TestRunnable implements
3. public void
4. while(true)    
5.             {    
6. "Thread is running..."
7. long time = System.currentTimeMillis();//去系统时间的毫秒数  
8. while((System.currentTimeMillis()-time < 1000)) {    
9. //程序循环1秒钟,不同于sleep(1000)会阻塞进程。  
10.             }    
11.               }    
12.        }    
13. }    
14. public class
15. public static void
16. new
17. new
18.                th1.start();    
19.                th1.interrupt();             
20.         }    
21. }    
22. /运行结果:一秒钟打印一次Thread is running...。程序没有终止的任何迹象

      上面的代码说明interrupt()并没有中断一个正在运行的线程,或者说让一个running中的线程放弃CPU。那么interrupt到底中断什么。

       首先我们看看interrupt究竟在干什么。

       当我们调用th1.interrput()的时候,线程th1的中断状态(interrupted status) 会被置位。我们可以通过Thread.currentThread().isInterrupted() 来检查这个布尔型的中断状态。

        在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断


Java代码  

java Thread根据线程名字停止 java线程interrupted_Java


1. //Interrupted的经典使用代码  
2. public void
3. try{    
4.              ....    
5. while(!Thread.currentThread().isInterrupted()&& more work to do){    
6. // do more work;  
7.              }    
8. catch(InterruptedException e){    
9. // thread was interrupted during sleep or wait  
10.         }    
11. finally{    
12. // cleanup, if required  
13.         }    
14. }


       很显然,在上面代码中,while循环有一个决定因素就是需要不停的检查自己的中断状态。当外部线程调用该线程的interrupt 时,使得中断状态置位。这是该线程将终止循环,不在执行循环中的do more work了。

       这说明: interrupt中断的是线程的某一部分业务逻辑,前提是线程需要检查自己的中断状态(isInterrupted())。

       但是当th1被阻塞的时候,比如被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞时。调用它的interrput()方法。可想而知,没有占用CPU运行的线程是不可能给自己的中断状态置位的。这就会产生一个InterruptedException异常。


Java代码  

java Thread根据线程名字停止 java线程interrupted_Java


    1. //中断一个被阻塞的线程代码
    2. class TestRunnable implements
    3. public void
    4. try{  
    5. 1000000); //这个线程将被阻塞1000秒
    6. catch(InterruptedException e){  
    7.          e.printStackTrace();  
    8. //do more work and return.
    9.           }  
    10.      }  
    11. }  
    12. public class
    13. public static void
    14. new
    15. new
    16. //开始执行分线程
    17. while(true){  
    18. //中断这个分线程
    19.         }  
    20.       }  
    21. }  
    22. /*运行结果:
    23.    java.lang.InterruptedException: sleep interrupted
    24.         at java.lang.Thread.sleep(Native Method)
    25.         at TestRunnable.run(TestDemo2.java:4)
    26.         at java.lang.Thread.run(Unknown Source)*/

     

    /* 
    * 如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下会发生,例如调用
    * Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,他们都可能永
    * 久的阻塞线程。即使发生超时,在超时期满之前持续等待也是不可行和不适当的,所以,要使
    * 用某种机制使得线程更早地退出被阻塞的状态。很不幸运,不存在这样一种机制对所有的情况
    * 都适用,但是,根据情况不同却可以使用特定的技术。使用Thread.interrupt()中断线程正
    * 如Example1中所描述的,Thread.interrupt()方法不会中断一个正在运行的线程。这一方法
    * 实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更
    * 确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,
    * 它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。因此,
    * 如果线程被上述几种方法阻塞,正确的停止线程方式是设置共享变量,并调用interrupt()(注
    * 意变量应该先设置)。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就
    * 将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最
    * 后线程都将检查共享变量然后再停止。下面示例描述了该技术。
    * */
    package Concurrency.Interrupt;
    
    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...");
    
    /*
    * 如果线程阻塞,将不会检查此变量,调用interrupt之后,线程就可以尽早的终结被阻 
    * 塞状 态,能够检查这一变量。
    * */
    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(2000);
    } catch (InterruptedException e) {
    // 接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态
    System.out.println("Thread interrupted...");
    }
    }
    
    System.out.println("Thread exiting under request...");
    }
    }
    /*
    * 把握几个重点: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方法执行完 毕,线程终止。
    * */