背景:楼主在项目开发中遇到一个问题,在Activity中需要起一个子线程执行耗时任务,Activity退出onDestroy后,释放资源。刚好子线程执行耗时任务的时候需要访问被释放的资源,进而发生了空指针异常的崩溃。

原因:主线程和子线程是并发的,主线程Activity何时退出释放资源,子线程何时访问资源,两者时序不可控。

1)加锁可以吗?

主线程Activity退出 释放资源时候加锁,;子线程执行Runnable时加锁,并且子线程执行任务之前判断是否已经释放资源。

这样可能会导致ANR问题:万一子线程耗时任务很久,主线程退出Activity时由于锁被子线程持有一直等待,有ANR风险。

2) 不加锁,使用volatile关键字标记是否释放变量

主线程退出Activity时,volatile变量 设置为true代表已经释放。子线程的runnable 执行之前判断volatile变量的值,如果为true代表资源是否,不再执行。

上线后依旧有零星崩溃上报:子线程的runnable判断volatile变量时候,资源还没释放。执行后续的逻辑,资源释放了造成崩溃。

时序: 子线程判断volatile变量,通过——主线程释放资源——子线程后续的逻辑访问资源

于是楼主想到,主线程退出Activity时,应该释放生命周期内使用的资源,包括子线程的Runnable,让Runnable不执行或者中断。——但是真的可以中断吗?

  • 有人说Handler的removeCallbacksAndMessages——对于未执行的Runnable,可以,但是对于已经跑起来的Runnable, 不行。
  • 有人说Thread.interrupt, 但是interrupt仅仅起到通知被停止线程的作用,实际上对于被停止的线程而言,它拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择压根不停止。——这个是Java 不提供强制停止线程机制。
  • 有人说线程池的shutdownNow方法,但是shtdownNow方法本质也还是给正在执行的线程发送interrupt。
  • 有人说使用线程池的Submit(Runnable runnable) 返回一个Future,   最后通过Future的cancel方法不就可以了??——楼主亲测,跑起来的Runnable 还是不行。

以上尝试,使用如下Demo验证, Activity Destroy后,Runnable依旧执行......

public class TestActivity extends Activity {private Runnable runnable;private HandlerThread handlerThread;private Handler handler;private Thread thread;private Future future;private ExecutorService executorService;private Handler mainHandler = new Handler(Looper.getMainLooper());public static void startActivity(Context context) {Intent intent = new Intent(context, TestActivity.class);context.startActivity(intent);}private void init() {runnable = new Runnable() {@Overridepublic void run() {while (true) {try{Thread.sleep(1000);Log.e("testing", "runnable run...." + TestActivity.this);} catch (Exception e) {Log.e("testing", "e run...." + e.toString());}}}};//1. handlerThread
//        handlerThread = new HandlerThread("test-handler-thread");
//        handlerThread.start();
//        handler = new Handler(handlerThread.getLooper());
//        handler.post(runnable);//2. Thread
//        thread = new Thread(runnable);
//        thread.start();//3. futureexecutorService = Executors.newSingleThreadExecutor();future = executorService.submit(runnable);}private void release() {//1.handlerThread
//        handlerThread.quit();
//        handler.removeCallbacks(runnable);//2. Thread
//        try {
//            thread.interrupt();
//        } catch (Exception e) {//        }//3. futureif(future != null) {boolean ret = future.cancel(true);executorService.shutdown();Log.e("testing", "future cancel...." + ret);}}@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {Log.e("testing", "act onCreate ");super.onCreate(savedInstanceState);setContentView(R.layout.activity_test);init();findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {TestActivity.this.finish();}});}@Overrideprotected void onDestroy() {release();Log.e("testing", "act onDestroy ");super.onDestroy();}
}

实际上,JAVA 推荐了使用Thread.currentThread().isInterrupted()的方法判断线程是否中断

也就是Demo中Runnable的 while(true) 修改为while(!Thread.currentThread().isInterrupted())

就Demo而言,可以实现中断Runnable,  但是实际项目的Runnable并不是一直循环,大多是一个耗费时间的任务。 Thread.currentThread().isInterrupted()判断不能一直贯穿整个Runnable, 只能在某一个时刻调用——万一在Runnable里调用isInterrupted()的时候线程还没interrupt,  调用isInterrupted()判断过后线程才interrupt, runnable仍然访问被释放的资源。

Runnable是否可以中断相关推荐

  1. linux服务器性能监控命令汇总(一)

    一.uptime 目录 一.uptime 1.使用 uptime 命令 2.以更人性化的格式显示时间 3.让 uptime 显示系统启动的日期/时间 4.获取版本信息和帮助信息 结论 二.top 1. ...

  2. Linux系统状态检测及进程控制--2

    Linux系统状态检测及进程控制--1(http://crushlinux.blog.51cto.com/2663646/836481) 4.僵死(进程已终止,但进程描述符存在,直到父进程调用wait ...

  3. 解决win10cpu使用率100_如何正确理解 CPU 使用率和平均负载的关系?看完你就知道了...

    来自公众号:阿里巴巴中间件 CPU(Central Processing Unit)是计算机系统的运算和控制核心,是信息处理.程序运行的最终执行单元,相当于系统的"大脑".当 CP ...

  4. python linux 优化_Linux性能优化(一)

    性能指标 性能优化的两个核心指标--"吞吐"和"延迟",这是从应用负载的视角来进行考察系统性能,直接影响了产品终端的用户体验.与之对应的是从系统资源的视角出发的 ...

  5. io密集型和cpu密集型_和小胖一起理解CPU负载和利用率

    作者:小胖前言 凌晨一点,正整着炸鸡的小胖,微信一呼"你的服务器CPU持续超载 - " 麻溜的连上服务器,先把CPU负载摁下来.仔细一想,最近1分钟平均负载很大,但CPU利用率却≤ ...

  6. linux 格式化up命令,uptime 命令介绍

    导读 Linux 小白,若对系统管理有兴趣,或想成为资深用户,就需要对命令行有扎实的功底.你需要知道很多命令,其中一个就是 uptime.文本我们会通过一些容易理解的案例来讲解一下这个命令的基本用法. ...

  7. java多线程系列(一)

    java多线程技能 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  8. 什么是interrupt

    什么是interrupt? interrupt是java中属于Thread的一个方法,调用它目的是给线程发出中断信号,但是不保证线程真的会中断.线程是否中断是由被通知的线程自己处理. 如果线程处于被阻 ...

  9. 一键获取linux内存、cpu、磁盘IO等信息脚本编写,及其原理详解

    一.脚本 今天主要分享一个shell脚本,用来获取linux系统CPU.内存.磁盘IO等信息. #!/bin/bash # 获取要监控的本地服务器IP地址 IP=`ifconfig | grep in ...

最新文章

  1. Python 技术篇-利用pymouse库操作windows系统电脑实现鼠标指针移动、点击
  2. 数据结构之表(5)栈的顺序实现
  3. C语言希尔排序(解析)
  4. 5.触摸touch,单点触摸,多点触摸,触摸优先和触摸事件的吞噬
  5. leetcode —— 16. 最接近的三数之和
  6. Java快速开发平台——JEECG 3.7.8 版本发布!我们的目标是有鱼丸也有粗面
  7. 第1章 程序设计和C语言
  8. ANSI Common Lisp 中文翻譯版 — ANSI Common Lisp 中文版
  9. Linux 基础——权限管理命令chown、chgrp
  10. SQL 常见的几种分页
  11. 第十一章 缓存机制——《跟我学Shiro》[张开涛]
  12. Matlab中 regionprops和bwlabel的用法
  13. 如何查找共享计算机的用户名和密码错误,访问共享文件夹提示“未知的用户名或密码错误...
  14. 服务器都没有显卡型号吗,云服务器都没显卡么?
  15. 关于jsp页面上无法显示图片的问题
  16. frp穿透你的远程桌面
  17. Android安卓原生接支付宝SDK支付客户端
  18. vue实现抽奖大转盘
  19. Java教程-Java 程序员们值得一看的好书推荐
  20. pytorch笔记(一)——tensor的storage()、stride()、storage_offset()

热门文章

  1. js 延期执行_js延迟执行函数
  2. 【小程序源码】王者荣耀改重复名,空白名最低战力查询助手
  3. 6.jQuery中的Ajax上传文件
  4. 勒索病毒发生变种 新文件名将带有“.UIWIX”后缀
  5. Intel笑了: 这才是骁龙835 Win10电脑的真实性能!
  6. Solaris系统管理-fmd日志清理
  7. 【ChatGPT】只需要2分钟,ChatGPT帮我生成了一份PPT
  8. ZnSe/ZnS量子点,硒化锌量子点,ZnSe/ZnS QDs(发射波长主要覆盖紫光和蓝光应用于QLED)
  9. android大版本ota,Android OTA升级新旧版本任意升级
  10. 漫谈程序员系列:一个老程序员的2014年终总结