美文网首页java并发学习
java并发中的interrupt()方法

java并发中的interrupt()方法

作者: 何甜甜在吗 | 来源:发表于2017-12-12 21:36 被阅读12次

    开门见山,interrupt()方法的作用,中断一些可以响应中断的阻塞任务(不过好像非阻塞的也可以被中断),如果不能响应中断,则调用该方法将不起作用

    阻塞状态:
    1.调用sleep(milliseconds)进入睡眠状态
    2.调用wait()/await()挂起了线程
    3.任务在等待某个输入/输出完成
    4.任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁

    其中3、4是不可以响应中断的。即调用中断

    测试代码:

    任务一:SleepBlocked.java

    /**
     * @author hetiantian
     * 可中断的阻塞
     */
    public class SleepBlocked implements Runnable {
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(100);  //当前线程睡眠100秒
            } catch (InterruptedException e) {
                System.out.println("InterruptedException");
            }
    
            System.out.println("Exiting SleepingBlocked.run()");
        }
    }
    

    任务二: IOBlockeded.java

    /**
     * @author hetiantian
     * 模拟IO阻塞,不可响应中断
     */
    public class IOBlockeded implements Runnable {
        private InputStream in;
    
        public IOBlockeded(InputStream in) {
            this.in = in;
        }
    
        @Override
        public void run() {
            try {
                System.out.println("Waiting for read():");
                in.read();
            }  catch (IOException e) {
                //如果当前被中断了的话
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("Interrupted from blocked I/O");
               } else {
                    throw new RuntimeException();
                }
            }
        }
    }
    

    任务三:SynchronizedBlocked.java

    /**
     * @author hetiantian
     * 模拟synchronized阻塞的情况
     */
    public class SynchronizedBlocked implements Runnable {
        //需要获得SynchronizedBlocke上的锁
    
        public synchronized void f() {
            while (true) {
                Thread.yield();  //让出cpu执行时间
            }
        }
    
        //构造函数中启动一个线程调用f()方法
        public SynchronizedBlocked() {
            new Thread() {
                public void run() {
                    f();
                }
            }.start();
        }
    
        @Override
        public void run() {
            System.out.println("trying to call f()");
            //继续调用需要锁的f()方法  //这个线程和构造方法中的线程不是同一个线程,不符合可重入
            f(); 
            System.out.println("Exiting SynchronizedBlocked.run()");
        }
    }
    

    测试类:Interrupting.java

    
    /**
     * @author hetiantian
     * 测试类
     */
    public class Interrupting {
        private static ExecutorService es = Executors.newCachedThreadPool();
    
        static void test(Runnable r) throws InterruptedException {
            Future<?> f = es.submit(r);
            TimeUnit.SECONDS.sleep(100);  //调用sleep()方法阻塞当前线程
            System.out.println("Interrupting " + r.getClass().getName());
            f.cancel(true);  //cancel中断由Executor启动的单个线程方法
            System.out.println("Interrupt sent to " + r.getClass().getName());
        }
    
        public static void main(String[] args) throws InterruptedException {
            test(new SleepBlocked());
            test(new IOBlockeded(System.in));
            test(new SynchronizedBlocked());
            TimeUnit.SECONDS.sleep(3);  //主线程睡眠3秒让其他线程有机会执行
            System.out.println("Aborting with System.exit(0)");
            System.exit(0);
        }
    }
    
    

    运行结果:

    Interrupting SleepBlocked
    Interrupt sent to SleepBlocked
    InterruptedException
    Waiting for read():
    Interrupting IOBlocked
    Interrupt sent to IOBlocked
    trying to call f()
    Interrupting SynchronizedBlocked
    Interrupt sent to SynchronizedBlocked
    Aborting with System.exit(0)
    

    分析运行结果:
    1.上述3、4的情况没有响应中断
    2.响应了中断以后将执行继续执行后面的代码,执行SleepBlocked任务,在中断以后继续执行了代码,如果不想要执行后面的代码,则通过在catch中加return来实现(我觉得加了return以后才是正真响应了中断,哪有中断了以后还能将后面的代码执行完毕的)

    修改以后的代码:

    public class SleepBlocked implements Runnable {
        @Override
        public void run() {
    
            try {
                TimeUnit.SECONDS.sleep(100);
            } catch(InterruptedException e) {
                System.out.println("InterruptedException");
                return;
            }
    
            System.out.println("Exiting SleepBlocked.run()");
        }
    }
    

    对于3、4的情形该怎么让它终端呢
    对于3
    1)关闭底层资源
    2)nio类提供了更人性的I/O中断(不是特别了解nio,只是敲过例子,不展开)
    代码如下:

    对于4
    好像没有办法解决了,难道资源就没办法释放了吗???

    对于线程中断还有其他方法:利用标识位,代码如下
    任务:Runner.java

    /**
     * @author hetiantian
     * 模拟一个任务
     */
    public class Runner implements Runnable {
        private long i;
    
        private volatile boolean on = true;  //用volatile修饰,保证了可见性
    
        @Override
        public void run() {
    
            while (on && !Thread.currentThread().isInterrupted()) {
                i++;
            }
    
            System.out.println("Count i = " + i);
         }
    
         //修改标识位
         public void cancel() {
            on = false;
         }
    }
    

    测试类:Shutdown.java

    /**
     * @author hetiantian
     * 一个测试类 
     */
    public class Shutdown {
        public static void main(String[] args) throws InterruptedException {
            Runner one = new Runner();
            Thread countThread = new Thread(one, "CountThread");
            countThread.start();
    
            //执行1秒以后后中断,这里中断采用的是调用interrupt()方法
            TimeUnit.SECONDS.sleep(1);
            countThread.interrupt();
    
            Runner two = new Runner();
            countThread = new Thread(two, "CountThread");
            countThread.start();
            //睡眠1秒,main线程对Runner two进行取消,on的状态由true--->false
            TimeUnit.SECONDS.sleep(1);
            two.cancel();
    
        }
    }
    

    但用标识位似乎有局限性,它适用于一个线程一直循环调用某个方法的情况次下,我想用标识位解决3、4情况的中断问题,失败了

    相关文章

      网友评论

      • cmazxiaoma:轮询标志位这种方法容易造成死锁
      • cmazxiaoma:volatile没有原子性哟
        何甜甜在吗:@cmazxiaoma 记错了,是禁止重排序,谢谢指出,改正下:whale:

      本文标题:java并发中的interrupt()方法

      本文链接:https://www.haomeiwen.com/subject/htznixtx.html