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

//在阻塞中终结
  线程的六种状态(网上有说五种,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 999
whileGo8 998
whileGo7 997
whileGo6 996
whileGo5 995
whileGo4 994
whileGo3 993
whileGo2 992
whileGo1 991
whileGo9 990
whileGo5 989
whileGo0 988
whileGo4 987
whileGo9 986
whileGo1 985
whileGo8 984
whileGo3 983
whileGo7 982
whileGo6 981
whileGo2 980
whileGo3 979
whileGo0 978
whileGo5 977
whileGo4 976
whileGo8 975
whileGo9 974
whileGo1 973
whileGo7 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值