• 并发编程003 --- 线程的取消与关闭


    要使线程安全、快速、可靠的停下来并非易事,java并未提供机制保证线程安全的停止,但是我们可以通过使用中断来完成线程的停止和关闭;

    本章节只总结基础线程的取消和关闭,类似封装库提供的方法如Future、线程池不在本章节讨论。

    1、interrupted方法

    Thread提供了中断相关的方法,这里需要注意的一点是,使用静态的interrupted方法,会清除线程的中断状态

     

     2、利用volatile变量作为标记,实现线程的关闭,前提是当前线程调用BlockingQ的produce方法,不会进入等待状态。

    public class Producer implements Runnable {
        private volatile boolean canceled = false;

    private BlockingQ blockingQ;

    public Producer(BlockingQ blockingQ) {
    this.blockingQ = blockingQ;
    }

    @Override
    public void run() {
    while (!canceled) {
    blockingQ.produce();
    }
    }

    public void cancel() {
    this.canceled = true;
    }
    }
     

    3、使用中断方法,实现线程终止或者关闭

    上述方法在一定场景下可以保证线程安全的终止,但是对于处于等待状态下的线程,上述方法是不生效的,因为当前线程无法重新检查取消标记

    此时需要使用Thread类的中断方法,实现一个更为健壮的线程取消方法,通常,阻塞方法object.wait(), Thread.sleep(), Thread.join()都会检查

    线程中断状态,如果处于中断状态,会清除中断状态,并抛出InterruptedException异常,此时线程并未被真正的中断

    下面的代码不会正常的关闭线程:由于清除了中断状态并在代码中捕获了该异常;外层判断中断状态时,线程一直执行;

    正确的方法是在外层捕获异常

        public void produce() {
            Integer value = new Random().nextInt();
    
            synchronized (lock) {
                while (this.valueList.size() >= MAX_SIZE) {
                    System.out.println("Thread " + Thread.currentThread().getName() + " produce wait.");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        System.out.println("Thread " + Thread.currentThread().getName() + " Produce interrupted!!");
                        System.out.println(Thread.currentThread().isInterrupted());
                    }
                }
    
                System.out.println("Thread " + Thread.currentThread().getName() + " produce value.");
                this.valueList.add(value);
                lock.notifyAll();
            }
        }
    public class Producer implements Runnable {
    
        private BlockingQ blockingQ;
    
        public Producer(BlockingQ blockingQ) {
            this.blockingQ = blockingQ;
        }
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
            while (!Thread.currentThread().isInterrupted()) {
                blockingQ.produce();
            }
        }
    }

    错误的执行结果:

    正确示例:

        public void produce() throws InterruptedException {
            Integer value = new Random().nextInt();
    
            synchronized (lock) {
                while (this.valueList.size() >= MAX_SIZE) {
                    System.out.println("Thread " + Thread.currentThread().getName() + " produce wait.");
                    lock.wait();
                }
    
                System.out.println("Thread " + Thread.currentThread().getName() + " produce value.");
                this.valueList.add(value);
                lock.notifyAll();
            }
        }
    public class Producer implements Runnable {
    
        private BlockingQ blockingQ;
    
        public Producer(BlockingQ blockingQ) {
            this.blockingQ = blockingQ;
        }
    
        @Override
        public void run() {
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    blockingQ.produce();
                }
            } catch (InterruptedException ex) {
                System.out.println(Thread.currentThread().getName() + " interrupted!!");
            }
        }
    }

    正确的执行结果:

     4、处理不可中断的阻塞

    并非所有的阻塞都可以使用中断来抛出InterruptedException异常来解除阻塞。

    这是因为这种阻塞不会检查中断状态,不可中断的阻塞一般有如下几种情况:

    ---java.io包中的Socket I/O方法

    ---java.io包中的I/O方法

    ---Selecter中的异步I/O

    ---获取锁

    关键步骤就是重写原来中断线程或者取消任务的方法,在方法里面加入自己的取消操作,比如关闭数据流,关闭套接字等,然后再调用父类的中断方法,这样就可以既关闭了阻塞的任务,又中断了线程。

    5、非正常线程终止

  • 相关阅读:
    购买 Linux VPS 服务器后简单的安全设置
    VPS性能测试:CPU内存,硬盘IO读写,带宽速度,UnixBench和压力测试
    Polysh实现多服务器批量执行shell
    第十一周编程总结
    第十周作业
    第九周编程总结修改
    第九周编程总结
    第八周编程总结
    第7周编程总结
    第七周编程总结啊
  • 原文地址:https://www.cnblogs.com/sniffs/p/11624179.html
Copyright © 2020-2023  润新知