文档章节

消失的线程

xpbob
 xpbob
发布于 2018/12/31 13:45
字数 992
阅读 24
收藏 0

很多小伙伴都问过我一个问题,就是任务线程跑着跑着消失了,而且没有任何异常日志。我都是条件反射式的回复,是不是用了线程池的submit提交任务。而且很大几率对方给予肯定答复。 解决方案,很多人都听过不少,下面我就分析一下原因以及最佳实践。

为什么消失

submit这个单词用的真的特别好,特别洋气,虽然可以用execute来提交,但是大部分人都是用的submit。问题也就出在submit上了。

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

submit也是调用的execute,而且是有Future的返回值的。他把一个Runnable 组装成了一个无返回类型的FutureTask。 FutureTask的run方法与众不同。

    public void run() {
		....
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
			....
        }
    }

可以看到FutureTask的run自己捕获了Throwable 而且没有抛出,线程里的所有代码出了什么错都会被捕获,并且赋值给了成员变量outcome。 最终在get里调用report有一段逻辑可以取出异常

    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

最后异常会在get的时候throw。 程序出错,异常被吞掉了,最终展现出业务线程消失的现象。

解决方案

run里自己编码解决异常

自己的代码健壮到一言不合来个大写的try catch 而且一定是Throwable并且要合理的记录 。写这种代码真心累,而且在一些特殊场合才这么干,例如javaagent。搞个探针上去,一堆异常在业务系统上,换谁谁都怕。

future.get()

submit的时候会返回一个Future,我们只要get就可以获取到异常。这个是一个理论可行的方案,这个也只用在有交互的场景,例如出现异常了再次提交任务等等。再交互的场景下,这个方案特别适合。

execute提交

submit最终也调用的execute。execute只能接收参数Runnable。 execute直接把异常给抛出了,就是不怎么优雅的记录。

        try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }

每个work执行的时候虽然也会捕获各种异常,但是最后都throw出来了,也能达到追踪的效果。

自定义线程池

继承线程池然后复写afterExecute(task, thrown);上面也看到了最后会执行这个方法,而且可以优雅的记录日志,以及可以做一些补偿操作再里面。

最佳实践

一般使用线程池都会自己去自定义,毕竟为了区别,我们会自己去写线程工厂去标识自己的线程,而且为了内存估计会调整阻塞队列的类型和大小,在一些压力突增的情况还得控制线程池里最大线程的个数与核心线程的比率,所以线程池的自定义是很有必要的。推荐使用自定义线程池的方式记录日志。并不推荐补偿等逻辑也写在线程池里,对于要补偿的情况推荐future.get()。这里只写异常的处理和补偿即可,日志就不用记录了。

© 著作权归作者所有

xpbob

xpbob

粉丝 98
博文 98
码字总数 80029
作品 0
高级程序员
私信 提问
Zookeeper应用之——栅栏(barrier)

Zookeeper应用之——栅栏(barrier) 栅栏(barrier)简介 barrier的作用是所有的线程等待,知道某一时刻,锁释放,所有的线程同时执行。举一个生动的例子,比如跑步比赛,所有 运动员都要在...

Java同学会
2018/07/03
0
0
Java引用传递和JVM堆栈的关系说明

通过代码说明 Java 引用传递在堆栈上的关系。 可以从JVM的内存空间存放上说明,值传递 和引用传递。 堆(线程共享):对象、对象的全局变量、数组 栈(线程私有):声明为局部变量的 基本数据...

冷基
02/23
0
0
iOS 实现后台上传文件队列

文件上传能实现 当控制器不消失的时候可以实现 控制器消失 在进来 还得继续上传 这个怎么实现 上传是一个线程 有点类似 迅雷下载 和 优酷爱奇艺等视频的 下载界面 怎么可以实现?

blueFriend
2017/07/24
69
0
中断状态与InterruptedExceptin异常的相互转换

调用interrupt方法后,可以中断掉线程。这里所说中断掉线程,是指下面其中一种结果。 (1)线程变成“中断状态”对“状态”的反应; (2)抛出“异常InterruptedException”对“控制”的反应...

恶魔在江湖
2014/02/18
0
0
如何写出线程不安全的代码

什么是线程安全性 很多时候,我们的代码,在单线程的环境下是可以运行的非常完美,然而,一旦把代码放到多线程的环境下去接受蹂躏,结果常常是惨不忍睹的。 《Java并发编程实践》中,给出了线...

SexyCode
2018/01/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Polymer dom-repeat how to notify array updated

Question: So I have this Polymer element with dom-repeat. It binds correctly. However, when the array is modified, it doesn't reflect back to DOM. Nothing changed when I click ......

孟飞阳
10分钟前
0
0
Spring-Boot 使用 mybatis-plus-gennretor代码生成器生成代码

1.导入需要的jar包 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> ......

小小小施爷
11分钟前
0
0
HanLP-地名识别调试方法

HanLP收词特别是实体比较多,因此特别容易造成误识别。下边举几个地名误识别的例子,需要指出的是,后边的机构名识别也以地名识别为基础,因此,如果地名识别不准确,也会导致机构名识别不准...

左手的倒影
31分钟前
0
0
ASP.NET Core系列(二):创建第一个.Net Core 项目

  新建项目      新建项目, 选择.NET Core 有如下几种类型可选, 分别是Console, ASP.NET Core 的空项目,Web API      我们选择ASP.NET Core Web App(MVC), 没有标注MVC的是采用R...

SEOwhywhy
32分钟前
0
0
springboot 引入 druid 数据源监控

Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。 第一步、引入依赖 <dependency><groupId>mysq...

嘴角轻扬30
32分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部