Java微服务架构师_Java 并发编程_006

并发编程有必要先了解 目前业务场景常见的问题:

问题2 :线程处理 多任务问题时对异常的不同处理

package com.gary.javastack.concurrent.aqs.safe;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 当一个Timer运行多个TimerTask时,只要其中一个TimerTask在执行中
 * 向run方法外抛出异常时,则其他任务也会自动终止。
 *
 * 推荐使用ScheduledThreadPoolExecutor的schedule,如果其中的一个
 * 任务抛出异常,其他任务则不受影响。之所以ScheduledThreadPoolExecutor
 * 的其他任务不受抛出异常的任务的影响,是因为在ScheduledThreadPoolExecutor中的
 * ScheduledFutureTask任务中catch掉了异常,但是在线程池任务的run方法内使用catch
 * 捕获异常并打印日志是最佳实战。
 */
public class TimerInterruptQue {
    // 创建定时器对象
    static Timer timer = new Timer();

    public static void main(String[] args) {
        // 添加任务1,延迟500ms执行
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("------one Task-------");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                throw new RuntimeException("error");
            }
        },500);

        // 添加任务2,延迟1000ms执行
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                for (;;){
                    System.out.println("------two Task-------");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },1000);
    }
}

执行效果截图:
在这里插入图片描述

解决方案的代码演示:

package com.gary.javastack.concurrent.aqs.safe;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestScheduledThreadPoolExecutor {

    static ScheduledThreadPoolExecutor poolExecutor = new ScheduledThreadPoolExecutor(1);

    public static void main(String[] args) {
        poolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("--------one Task----------");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                throw new RuntimeException("error");
            }
        }, 500, TimeUnit.MICROSECONDS);

        poolExecutor.schedule(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("--------two Task----------");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("");
            }
        }, 1000, TimeUnit.MICROSECONDS);

        poolExecutor.shutdown();
    }
}

执行效果截图:
在这里插入图片描述
总结:

  1. ScheduledThreadPoolExecutor的处理方式:

ScheduledThreadPoolExecutor
的其他任务不受抛出异常的任务的影响,是因为在ScheduledThreadPoolExecutor中的
ScheduledFutureTask任务中catch掉了异常

在这里插入图片描述

  1. Timer的处理方式如下:

在这里插入图片描述
具体处理逻辑 mainLoop()

/**
     * The main timer loop.  (See class comment.)
     */
    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        break; // Queue is empty and will forever remain; die

                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized(task.lock) {
                        if (task.state == TimerTask.CANCELLED) {
                            queue.removeMin();
                            continue;  // No action required, poll queue again
                        }
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        if (taskFired = (executionTime<=currentTime)) {
                            if (task.period == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }
    }
}

在这里插入图片描述

当任务在执行过程中抛出除了InterruptedExeception之外的异常时,唯一的消费线程TimerThread就会因为抛出异常而终止,那么任务队列中的其他执行的任务就会被清除掉,所以在TimerTask的run方法内最好使用try
catch结构捕获可能的异常,不要把异常抛出到run方法之外。

编码建议:

ScheduledThreadPoolExecutor是jdk并发包提供的组件,其功能包含但不限于Timer。Timer是固定的多线程生产任务
单线程消费任务,但是ScheduledThreadPoolExecutor是可以配置的,既可以是多线程生产单线程消费模式也可以是多线程生产多线程消费,所以在日常开发中使用定时器功能时应该优先使用ScheduledThreadPoolExecutor

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder_Boy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值