初阶并发编辑之——线程状态与线程中断

来源:互联网 发布:欧洲卡车模拟2 mac 编辑:程序博客网 时间:2024/06/12 04:38

//在阻塞中终结
  线程的六种状态(网上有说五种,Thinking in Java中说四种,我这里以jdk1.8的API为主,jdk1.5开始都是6种):
  1)新建NEW

  当线程Thread()被创建后,调用start()方法之前,尚未启动的线程处于此状态。

  2)可运行RUNNABLE

  线程调用start(),并占有CUP时间,在Java虚拟机中执行的线程处于此状态,但它可能正在等待来自操作系统(例如处理器)的其他资源。

  3)阻塞BLOCKED

  一个线程的线程状态阻塞等待监视器锁定。处于阻塞状态的线程正在等待监视器锁定进入同步块/方法,或者在调用Object.wait后重新输入同步的块/方法。

  4)等待WAITING

  等待状态的线程正在等待另一个线程执行特定的动作。 例如,已经在对象上调用Object.wait()线程正在等待另一个线程调用该对象上Object.notify() Object.notifyAll()或。 调用Thread.join()的线程正在等待指定的线程终止。

  5)计时等待TIMED_WAITING

  具有指定等待时间的某一等待线程的线程状态。

  6)死亡TERMINATED

  已终止线程的线程状态。线程已运行完毕。它的run()方法已正常结束或通过抛出异常而结束。线程的终止run()方法,线程结束。

  现在我们逐一分析各个状态:

  当新建一个线程时,它已经分配了必须的系统资源,并执行了初始化,已经有资格获取cpu时间,就好比排队上厕所,你可以有资格抢占厕所。一旦调度器调用就进入运行状态。进入可运行状态的线程可能正在运行中,也可能没有运行,取决于操作系统给线程提供的时间。线程开始运行,它不必保持运行。运行中的线程被中断目的就是让其他线程获得机会。比如正在运行的线程调用yield方法,或者被堵塞(一般如IO中等待输入是堵塞)就会让出cpu,就好像你进去厕所后呆一会又出来让别人先用。被堵塞线程和等待线程都是线程从运行到停止运行,都暂时停止线程的执行。不同的是线程被堵塞是被动堵塞,在持有对象的同步块或者方法中(比如synchronized块或者方法,非java.util.concurrent库中的锁)已经有线程抢占,就会进入堵塞状态。而等待线程是主动的,在满足条件后再去运行,操作系统中知道什么时候停止等待,就比如main主程序中在t1和t2的start()方法中添加t1.join(),就会让main主线程进入等待,当t1线程运行完毕再激活main主线程去执行t2.start()。至于计时等待就是在等待的基础上添加等待的时间。比如方法sleep(100)和其他限制时间的方法。而被终止的线程进入死亡状态如下两个原因:run方法正常退出而自然死亡。因为一个没有捕获的异常而意外死亡。

  各状态的转换如下图:
这里写图片描述

中断
  Thread类的静态方法interrupt()方法可以中断被阻塞的任务,这个方法将改变中断状态。如果一个线程已经被堵塞,或者试图执行堵塞操作,那么设置这个中断状态将会抛出一个InterrupttedException,当抛出该异常时或者调用Thread.interrupted()方法时(注意这里,是interrupted(),不是interrupt()方法,api对这个方法的解释是:测试当前线程是否中断。 该方法可以清除线程的中断状态 。换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。),中断状态会复位,变会原来的状态。interrupt()方法必须持有Thread对象,但是也可以使用Executor中方法shutdownNow()将发送一个interrupt()给它控制的所有线程。现在我们看一个用10个线程将1000递减的代码实例:

class whileGo implements Runnable{    private static volatile boolean isGo;    public int id;    public volatile static int value = 1000;    public static  int getValue(){        return value;    }    public static void Stop(){        isGo = false;    }    public whileGo(int i){        isGo = true;        this.id = i;    }    @Override    public void run() {        // TODO Auto-generated method stub            //System.out.println("whileGo----------interruptState:  "+Thread.currentThread(). isInterrupted());            try {                while(true){                synchronized(whileGo.class){                    --value;                    System.out.println("whileGo"+this.id+" "+getValue());                }                TimeUnit.MILLISECONDS.sleep(100);                /*if(Thread.interrupted()){                    System.out.println(Thread.interrupted());                    //Stop();                }*/                }            } catch (InterruptedException e) {                System.out.println("捕获线程"+this.id+"异常InterruptedException并中断该线程!");            }    }}public class InterruptTest1 {      public static void main(String[] args) {          ExecutorService exec = Executors.newCachedThreadPool();          for(int i=0;i<10;i++){              exec.execute(new whileGo(i));          }          try {            TimeUnit.MILLISECONDS.sleep(200);   //将主线程休眠0.2秒,再执行终止操作。            exec.shutdownNow();               } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();           }      }}输出结果如下:whileGo0 999whileGo8 998whileGo7 997whileGo6 996whileGo5 995whileGo4 994whileGo3 993whileGo2 992whileGo1 991whileGo9 990whileGo5 989whileGo0 988whileGo4 987whileGo9 986whileGo1 985whileGo8 984whileGo3 983whileGo7 982whileGo6 981whileGo2 980whileGo3 979whileGo0 978whileGo5 977whileGo4 976whileGo8 975whileGo9 974whileGo1 973whileGo7 972捕获线程9异常InterruptedException并中断该线程!捕获线程0异常InterruptedException并中断该线程!捕获线程3异常InterruptedException并中断该线程!捕获线程8异常InterruptedException并中断该线程!捕获线程1异常InterruptedException并中断该线程!捕获线程4异常InterruptedException并中断该线程!捕获线程7异常InterruptedException并中断该线程!捕获线程6异常InterruptedException并中断该线程!捕获线程2异常InterruptedException并中断该线程!捕获线程5异常InterruptedException并中断该线程!`

  再编写这个代码的时候我遇到了这几个问题,可以和大家分享以下:

  第一:在run()方法中的同步块synchronized中的()我刚开始是写this的,发现value值被没有被锁住。后来我才发现,我设置value为static,那么他就应该是属于类whileGo的,对象锁是所不主的,应该锁的是类。总结一下就是你在同步块中锁的东西属于什么就设置什么锁,锁的是对象中的状态就锁对象,锁的是类中 的静态变量就锁类。

  第二:本来方法getValue()我是加锁的,但是发现唯一调用到该方法的代码已经在锁中了,加锁就毫无意义了。

  第三:大家看到我下面注释的代码部分,本来我的理解是在主线程中执行器将各个线程的中断状态改变为ture,然后在run中的while循环中用interrupted()判断中断状态再去stop任务,结果线程一直无法中断。输出Thread.currentThread().interrupted()发现一直是flase。原来当抛出异常interruptException或者调用interrupted()方法时中断状态会复位回到false。正确的思路应该时将try-catch语句与中断机制结合,再抛出interruptException,注意的是while循环一定要在try中不然无法中断。

//if(Thread.interrupted()){//                  Stop();//              }


  不过interrupt()不可中断I/O和再synchronized块上的等待。在I/O中调用interrupt()不会抛出interruptException异常。

阅读全文
0 0
原创粉丝点击