并发编程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!!");
        }
    }
}

正确的执行结果:

原文地址:https://www.cnblogs.com/sniffs/p/11624179.html

时间: 2024-10-15 08:29:50

并发编程003 --- 线程的取消与关闭的相关文章

《Java并发编程实战》笔记-取消与关闭

1,中断是实现取消的最合理方式.2,对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己.3,区分任务和线程对中断的反应是很重要的4,线程有一个相应的所有者,即创建该线程的类.5,除非拥有某个线程,否则不能对该线程进行操控.由于每个线程拥有各自的中断策略,因此除非你知道中断对该线程的含义,否则就不应该中断这个线程.

并发编程 13—— 线程池 之 整体架构

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线

并发编程 15—— 线程池 之 原理二

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线

并发编程 14—— 线程池 之 原理一

Java并发编程实践 目录 并发编程 01—— ConcurrentHashMap 并发编程 02—— 阻塞队列和生产者-消费者模式 并发编程 03—— 闭锁CountDownLatch 与 栅栏CyclicBarrier 并发编程 04—— Callable和Future 并发编程 05—— CompletionService : Executor 和 BlockingQueue 并发编程 06—— 任务取消 并发编程 07—— 任务取消 之 中断 并发编程 08—— 任务取消 之 停止基于线

【转】Java并发编程:线程池的使用

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

Java并发编程:线程池的使用(转)

Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPool

Java并发编程:线程的同步

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

Java并发编程:线程的创建

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

68:Scala并发编程原生线程Actor、Cass Class下的消息传递和偏函数实战解析及其在Spark中的应用源码解析

今天给大家带来的是王家林老师的scala编程讲座的第68讲:Scala并发编程原生线程Actor.Cass Class下的消息传递和偏函数实战解析 昨天讲了Actor的匿名Actor及消息传递,那么我们今天来看一下原生线程Actor及CassClass下的消息传递,让我们从代码出发: case class Person(name:String,age:Int)//定义cass Class class HelloActor extends Actor{//预定义一个Actor  def act()