博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入浅出 Java Concurrency (36): 线程池 part 9 并发操作异常体系[转]
阅读量:4481 次
发布时间:2019-06-08

本文共 2603 字,大约阅读时间需要 8 分钟。

并发包引入的工具类很多方法都会抛出一定的异常,这些异常描述了任务在线程池中执行时发生的例外情况,而通常这些例外需要应用程序进行捕捉和处理。

例如在Future接口中有如下一个API:

 

java.util.concurrent.Future.get(long, TimeUnit) throws InterruptedException, ExecutionException, TimeoutException;

 

在中描述了Future类的具体实现原理。这里不再讨论,但是比较好奇的抛出的三个异常。

这里有一篇文章()描述了InterruptedException的来源和处理方式。简单的说就是线程在执行的过程中被自己或者别人中断了。这时候为了响应中断就需要处理当前的异常。

对于java.lang.Thread而言,InterruptedException也是一个很诡异的问题。

中断一个线程Thread.interrupt()时会触发下面一种情况:

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

检测一个线程的中断状态描述是这样的Thread.interrupted():

测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。 

也就是说如果检测到一个线程已经被中断了,那么线程的使用方(挂起、等待或者正在执行)都将应该得到一个中断异常,同时将会清除异常中断状态。

 

V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
    if (!tryAcquireSharedNanos(0, nanosTimeout))
        throw new TimeoutException();
    if (getState() == CANCELLED)
        throw new CancellationException();
    if (exception != null)
        throw new ExecutionException(exception);
    return result;
}

 

上面获取任务结果的方法实现中,将在获取锁的过程中得到一个中断异常。代码java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(int, long)描述了这种情况:

    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    return tryAcquireShared(arg) >= 0 ||
        doAcquireSharedNanos(arg, nanosTimeout);
    }

 

 

这里在获取锁的时候检测线程中断情况,如果被中断则清除中断位,同时抛出一个中断异常。为什么如此做?因为我们的线程在线程池中是被重复执行的,所以一旦线程被中断后并不会退出线程,而是设置中断位,等候任务队列自己处理线程,从而达到线程被重复利用的目的。有兴趣的可以参考代码java.util.concurrent.ThreadPoolExecutor.Worker.runTask(Runnable)。这里在关闭线程池时就会导致中断所有线程。

除了InterruptedException 异常我们还发现了一个全新的异常java.util.concurrent.TimeoutException,此异常是用来描述任务执行时间超过了期望等待时间,也许是一直没有获取到锁,也许是还没有执行完成。

在innerGet代码片段中我们看到,如果线程在指定的时间无法获取到锁,那么就会得到一个超时异常。这个很好理解,比如如果执行一个非常耗时的网络任务,我们不希望任务一直等待从而占用大量的资源,可能在一定时间后就会希望取消此操作。此时超时异常很好的描述了这种需求。

与此同时,如果取消了一个任务,那么再次从任务中获取执行结果,那么将会得到一个任务被取消的异常java.util.concurrent.CancellationException。

除了上述异常外,还将得到一个java.util.concurrent.ExecutionException异常,

这是因为我们的提交的任务java.util.concurrent.Callable在call()方法中允许抛出任何异常,另外常规的线程执行也可能抛出一个RuntimeException,所以这里简单包装了下所有异常,当作执行过程中发生的异常ExecutionException抛出。

以上就是整个异常体系,所有并发操作的异常都可以归结于上述几类。

很多情况下处理时间长度都是用java.util.concurrent.TimeUnit,这是一个枚举类型,用来描述时间长度。其中内置了一些长度的单位。其中包括纳秒、微秒、毫秒、秒、分、时、天。例如超时操作5秒,可以使用

Future.get(5,TimeUnit.SECONDS) 或者 Future.get(5000L,TimeUnit.MILLISECONDS)

当然一种单位的时间转换成另一种单位的时间也是非常方便的。另外还有线程的sleep/join以及对象的wait操作的便捷操作。

转载于:https://www.cnblogs.com/0x2D-0x22/p/4138799.html

你可能感兴趣的文章
【嵌入式开发】写入开发板Linux系统-模型S3C6410
查看>>
C# 子线程与主线程通讯方法一
查看>>
006——修改tomacat的编码
查看>>
《C程序设计语言》笔记 (八) UNIX系统接口
查看>>
git常用命令
查看>>
Android必知必会-获取视频文件的截图、缩略图
查看>>
(转)理解Bitblt、StretchBlt与SetDIBitsToDevice、StretchDibits
查看>>
ViurtualBox配置虚拟机Linux的网络环境
查看>>
VLC 媒体播放器
查看>>
\n ^ \t的使用
查看>>
css盒模型
查看>>
探索式测试:测试自动化
查看>>
make install fping
查看>>
面试笔试题
查看>>
MySql可视化工具MySQL Workbench使用教程
查看>>
个人站立会议第二阶段07
查看>>
云时代架构阅读笔记五——Web应用安全
查看>>
IOS 单击手势和cell点击冲突
查看>>
学习_HTML5_day3
查看>>
计算机网络与应用第二次笔记
查看>>