import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args){
//        CaptureThreadException.test();
//        EmptyException.test();
//        ThreadHook.test();
        PreventDuplicated.test();
    }
}

/*
    7.1 获取线程运行时异常

        public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
            :为某个线程指定UncaughtExceptionHandler
        public UncaughtExceptionHandler getUncaughtExceptionHandler();
            :获取某个线程的UncaughtExceptionHandler

        public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
            :设置全局的UncaughtExceptionHandler
        public static void setDefaultUncaughtExceptionHandler(UncaughtException eh)
            :获取全局的UncaughtExceptionHandler

    函数接口,该回调接口会被Thread中的dispatchUncaughtExcept方法调用,当线程在运行
    的过程中出现了异常时,JVM会调用dispatchUncaughtExcept方法,该方法将对应的线程实
    例以及异常信息传递给回调接口:
        public interface UncaughtExceptionHandler{
            void uncaughtException(Thread t, Throwable e);
        }

        private void dispatchUncaughtExcept(Throwable e){
            getUncaughtExceptionHandler().uncaughtException(this.e);
        }

    闲谈:
        在平时的工作中,这种设计方式是比较常见的,尤其是那种异步执行方法,不如Google的
        guava toolkit就提供了EventBus,在EventBus中事件源和实践的subscriber两者
        借助于EventBus实现了完全的解耦合,但是在subscriber执行任务时有可能会出现异常
        情况,EventBus同样也是借助一个ExceptionHandler进行回调处理的。
 */
class CaptureThreadException{
    public static void test() {
        Thread.setDefaultUncaughtExceptionHandler((t,e)->{
            System.out.println(t.getName()+" occur exception");
            e.printStackTrace();
        });

        final Thread t = new Thread(()->{
            try{
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {

            }
            System.out.println(1/0);
        },"Test-Thread");

        t.start();
    }
}

/*
    7.1.3 UncaughtExceptionHandler源码分析

    未注入UncaughtExceptionHandler回调接口的情况下,就从ThreadGroup中获取:
        1.该ThreadGroup如果有父ThreadGroup,则直接使用父Group的UncaughtException
        2.如果设置了全局默认的UncaughtExceptionHandler,则调用UncaughtException
        3.既没有父,又没有全局的,则直接将异常的堆栈信息定向到System.err中

    案例分析:
        由于没有指定,所以寻找过程为:
            线程出现异常=>Main Group=>System Group=>System.err
 */

class EmptyException{
    public static void test() {
        ThreadGroup main = Thread.currentThread().getThreadGroup();
        System.out.println(main.getName());
        System.out.println(main.getParent());
        System.out.println(main.getParent().getParent());

        final Thread thread = new Thread(()->{
            try{
                TimeUnit.SECONDS.sleep(2);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(1/0);
        },"Test-Thread");

        thread.start();
    }
}

/*
    7.2.1 Hook线程介绍

    Jvm进程的退出是由于JVM进程没有活跃的非守护线程,或者系统中断了信号。向JVM程序
    注入多个Hook线程,在JVM进程退出的时候,Hook线程会启动执行,通过Runtime可以为
    JVM注入多个Hook线程。
 */

class ThreadHook{
    public static void test() {
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run(){
                try{
                    System.out.println("The hook thread 1 is running...");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("The hook thread 1 will exit.");
            }
        });

        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run(){
                try{
                    System.out.println("The hook thread 2 is running...");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("The hook thread 2 will exit.");
            }
        });
    }
}

/*
    7.2.2 Hook线程实战

    需求:
        在我们开发中经常会遇到Hook线程,比如为了防止某个程序被重复启动,在进行启动时
        会创建一个lock文件,进程收到中断信号的时候会删除这个lock文件,我们在mysql服
        务器、zookeeper、kafka等系统中都能看到lock文件的存在,本节,将利用hook线程
        的特点,模拟一个防止重复启动的线程。
 */
class PreventDuplicated {
    private final static String LOCK_PATH = "C:\\Users\\Administrator\\Desktop\\JavaAPI";
    private final static String LOCK_FILE = ".lock";
    private final static String PERMISSIONS = "rw-------";

    private static Path getLockFile(){
        return Paths.get(LOCK_PATH,LOCK_FILE);
    }

    private static void checkRunning(){
        Path path = getLockFile();

        if(path.toFile().exists()){
            throw new RuntimeException("The program already running...");
        }

        /*
            很尴尬一点,这个地方貌似是针对Linux的写法,我这个地方出现了问题,
            暂时先将这个问题放一下吧。。。
         */
        Set<PosixFilePermission> perms = PosixFilePermissions.fromString(PERMISSIONS);

        try {
            Files.createFile(path,PosixFilePermissions.asFileAttribute(perms));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void test(){
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                System.out.println("The program received kill SIGNAL.");
                getLockFile().toFile().delete();
            }
        });

        checkRunning();

        while (true) {
            try{
                TimeUnit.MILLISECONDS.sleep(1);
                System.out.println("program is running...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/*
    7.2.3 Hook线程应用场景及注意事项
        1.Hook线程只有在收到退出信号的时候会被执行,如果kill使用了-9,那么
            Hook线程不会执行,因此lock文件也不会被清理
        2.Hook线程中也可以执行一些资源的释放工作,如关闭文件句柄、socket链接
            、数据库connection等
 */

《Java高并发编程详解》笔记

Java的Hook线程及捕获线程执行异常的更多相关文章

  1. C#通过接口与线程通信(捕获线程状态)介绍

    C#通过接口与线程通信(捕获线程状态)介绍 摘要:本文介绍C#通过接口与线程通信(捕获线程状态),并提供简单的示例代码供参考. 提示:本文所提到的线程状态变化,并不是指线程启动.暂停.停止,而是说线程 ...

  2. java并发编程(四) 线程池 & 任务执行、终止源码分析

    参考文档 线程池任务执行全过程:https://blog.csdn.net/wojiaolinaaa/article/details/51345789 线程池中断:https://www.cnblog ...

  3. Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程

    Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程 一.捕获异常并重新启用线程 public class Testun { public static voi ...

  4. 死磕 java线程系列之线程池深入解析——普通任务执行流程

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了Java中 ...

  5. java主线程等待所有子线程执行完毕在执行(常见面试题)

    java主线程等待所有子线程执行完毕在执行(常见面试题) java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个 ...

  6. Java中主线程如何捕获子线程抛出的异常

    首先明确线程代码的边界.其实很简单,Runnable接口的run方法所界定的边界就可以看作是线程代码的边界.Runnable接口中run方法原型如下: public void run(); 而所有的具 ...

  7. 死磕 java线程系列之线程池深入解析——未来任务执行流程

    (手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了线程池中普 ...

  8. 【Java多线程系列四】控制线程执行顺序

    假设有线程1/线程2/线程3,线程3必须在线程1/线程2执行完成之后开始执行,有两种方式可实现 Thread类的join方法:使宿主线程阻塞指定时间或者直到寄生线程执行完毕 CountDownLatc ...

  9. Java主线程如何等待子线程执行结束(转)

    工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一个线程启动之后, 是异步的去执行需要执行的内容的, 不会影响主线 ...

随机推荐

  1. DataTable 更改在有数据列的类型方法

    原文:DataTable 更改在有数据列的类型方法 /// <summary> /// 修改数据表DataTable某一列的类型和记录值(正确步骤:1.克隆表结构,2.修改列类型,3.修改 ...

  2. 【SQL Server】SQL Server占用CPU使用率100%的解决方法

    原文:[SQL Server]SQL Server占用CPU使用率100%的解决方法 近日,帮一个客户解决了服务器CPU占用率高达100%的问题. 以前做的一个某污水处理厂自控系统项目,客户反映其自控 ...

  3. 论文阅读计划1(Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming & An Enforcement of Real Time Scheduling in Spark Streaming & StyleBank: An Explicit Representation for Neural Ima)

    Benchmarking Streaming Computation Engines: Storm, Flink and Spark Streaming[1] 简介:雅虎发布的一份各种流处理引擎的基准 ...

  4. 使用百度网盘+Git,把版本控制托管到云端,附精彩评论

    http://www.cnblogs.com/vajoy/p/3929675.html 我试过多个这种双向同步的网盘,在网络状况不好.系统卡顿以及某些程序BUG的情况下,同步会有错乱现象,尤其是多个电 ...

  5. 全部的Windows消息对应值

    以下是全部的Windows消息,   对于未在MSDN上的消息的WPARAM,   LPARAM参数解释正确的给分 [已知   :0x0313,   0x01e2,   0x01e5,   0x01e ...

  6. 如何用C++操作无线网卡开启共享热点WiFi?

    首先需要笔记本具备AP热点功能,记得写好的程序必须用管理员身份运行. 准备工作需要先做好 //查看是否支持的承载网络 netsh wlan show drivers //设置网络模式为allow ne ...

  7. csdn token

    http://download.csdn.net/download/pp_haitun/9614126 http://dl.download.csdn.net/down11/20160826/28b9 ...

  8. Qt+VS编译器:默认库“library”与其他库的使用冲突;使用 /NODEFAULTLIB:library(我曾经碰到过,修改qmake.conf,但我修改的是VS的IDE配置)good

    找到qt安装目录下的mkspecs文件夹,在里面找到你使用的对应版本编译器,打开qmake.conf.稍等: /MD:动态链接多线程库(msvcrt.lib).使用该选项时,需要用/NODEFAULT ...

  9. canvas的进阶 - 学习利用canvas做一个炫酷的倒计时功能

    先给大家贴一张图片,因为我不会上传视频( ̄□ ̄||) ,请大家谅解了~  如果有知道怎么上传视频的大神还请指点指点 ^_^ ~ 然后看一下代码: html部分 :  <!DOCTYPE html ...

  10. 十分钟了解Kubernetes

    何为Kubernetes? 最简单的一句话来概括Kubernetes. 它就是一套成熟的商用服务编排解决方案.Kubernetes定位在Saas层,重点解决了微服务大规模部署时的服务编排问题. Kub ...