热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

线程一1.0线程获取线程的运行时异常,Hook线程

下图:线程在执行单元中是不允许抛出checked异常的,,而且线程运行在自己的上下文中,派生他的线程将无法直接获得它运行中出

下图:

线程在执行单元中是不允许抛出checked异常的,,而且线程运行在自己的上下文中,派生他的线程将无法直接获得它运行中出现的异常信息,对此Java给我们提供了一个uncaughtexceptionHandler接口,当线程在运行过程中出现异常时,就会回调UncaughtExceptionHandler接口,从而得知那个线程在运行中出错,以及出现了什么样的错误,如下

public static void main(String[] args) {
        try{
            Thread t =new Thread(new Runnable(){
                @Override
                public void run() {
                    int i = 10/0;
                    System.out.println("run....");
                }
            });
            t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t,   Throwable e) {
                    System.out.println("catch 到了"+t.getName());
                    e.printStackTrace();
                }
            });
            t.start();
        }catch(Exception e){
            System.out.println("catch 不到");
        }
    }

结果如下:

public static void main(String[] args) {
        try{
            Thread t =new Thread(new Runnable(){
                @Override
                public void run() {
                    int i = 10/0;
                    System.out.println("run....");
                }
            });
            t.start();
        }catch(Exception e){
            System.out.println("catch 不到");
        }
    }

二》 uncaughtExceptionHandker 源码分析

在没有向线程注入uncaughtExceptionHandler回调接口的时候线程若是出现了异常该怎么办?

get方法首先会判断当前线程中是否设置了handler,有则执行线程自己的uncaughtException 方法,否则就到 所在的threadgroup中获取,threadgroup同样也实现了uncaugthExceptionHandler接口,看看threadgroup里面的uncaught-Exception:

该threadgroup如果有父threadgroup,则直接调用父group的uncaughtException,

如果设置了全局默认的uncaughtexceptionHandler,则调用uncaughtException方法,

若既没有父threadgroup,也没有设置全局的默认uncaughtException,则会直接将异常的堆栈信息定向到system,err中

public static void main(String[] args) {
        ThreadGroup maingroup=Thread.currentThread().getThreadGroup();
        System.out.println(maingroup.getName());
        System.out.println(maingroup.getParent());
        System.out.println(maingroup.getParent().getParent());
        final Thread thread=new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                // TODO: handle exception
            }
        
            System.out.println(1/0);
        },"test-thread");
        thread.start();
    }

上面代码没有设置默认的handler,也没有对thread指定handler,因此当thread出现异常的时候,会向上寻找group的uncaughtException,如图:

三  注入钩子线程:

hook线程:

jvm的退出是由于jvm进程中没有活跃的非守护线程,或者收到了系统的中断信号,向jvm程序中注入了一个Hook线程,在jvm进城退出的时候,Hook线程会启动执行,通过Runtime可以为jvm注入多个Hook线程,例子:

public static void main(String[] args) {
     Runtime.getRuntime().addShutdownHook(new Thread() {
         @Override
        public void run() {
             try {
                 System.out.println("the hook thread 1 is running.");
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
                
            }
             System.out.println("the hook thread 1 will exit.");
        }
     });
     //可以注入多个
     Runtime.getRuntime().addShutdownHook(new Thread() {
         @Override
        public void run() {
             try {
                 System.out.println("the hook thread 2 is running.");
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
                
            }
             System.out.println("the hook thread 2 will exit.");
        }
     });
    } 

java 注入了两个Hook线程,在main线程中结束,也就是jvm中没有了活动的非守护线程,jvm即将推出的时候,两个Hook线程会被启动并且运行,结果如下:

在我们开发中经常会遇到Hook线程,比如为了防止某个程序被重复启动,在进程启动时会创建一个lock文件,进程收到中断信号的时候会删除这个lock文件的存在, 模拟一个利用Hook线程防止重复启动的程序,;

public class ThreadGroupCreator {
    private final static String LOCK_PATH="/wenjian/home";
    private final static String LOCK_FILE=".lock";
    private final static String PERMISSIONS="rw-------";
    public static void main(String[] args) throws IOException{
    Runtime.getRuntime().addShutdownHook(new Thread(()->{
        System.out.println("the program received kill signal.");
        getLockFile().toFile().delete();
        
    }));
        checkckRunning();
        for(; ;) {
            try {
                TimeUnit.MILLISECONDS.sleep(1);
                System.out.println("program is running.");
            } catch (Exception e) {
                e.printStackTrace();
                
            }
        }
    }
    private static void checkckRunning() throws IOException {
        Path path=getLockFile();
        if (path.toFile().exists()) {
            throw new RuntimeException("the program already running.");
        }
        Setperms=PosixFilePermissions.fromString(PERMISSIONS);
        Files.createFile(path, PosixFilePermissions.asFileAttribute(perms));
    }
    private static Path getLockFile() {
        return java.nio.file.Paths.get(LOCK_PATH, LOCK_FILE);
    }
}

运行发现多了个.lock文件

执行kill pid jvm收到中断信号,并且启动Hook线程,删除。,lock 文件 输出如下

 

Hook线程只会在收到退出信号的时候会被执行,如果在kill的时候使用了参数-9,那么Hook线程不会得到执行,进程会立即退出,因此。lock文件得不到清理

Hook线程中也可以执行一些资源释放的工作,比如关闭文件句柄,socket 连接。数据库的connection等

尽量不要再Hook线程中执行一些非常耗时非常浪费时间的操作,会导致程序迟迟不能退出

 


推荐阅读
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • JVM钩子函数的应用场景详解
    本文详细介绍了JVM钩子函数的多种应用场景,包括正常关闭、异常关闭和强制关闭。通过具体示例和代码演示,帮助读者更好地理解和应用这一机制。适合对Java编程和JVM有一定基础的开发者阅读。 ... [详细]
  • Java 中的等时日期(int,int)方法,示例 ... [详细]
  • Java设计模式详解:解释器模式的应用与实现
    本文详细介绍了Java设计模式中的解释器模式,包括其定义、应用场景、优缺点以及具体的实现示例。通过音乐解释器的例子,帮助读者更好地理解和应用这一模式。 ... [详细]
  • 普通树(每个节点可以有任意数量的子节点)级序遍历 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 深入理解Java中的多态性概念及其应用
    多态是面向对象编程中的三大核心特性之一,与封装和继承共同构成了面向对象的基础。多态使得代码更加灵活和可扩展,封装和继承则为其提供了必要的支持。本文将深入探讨多态的概念及其在Java中的具体应用,帮助读者全面理解和掌握这一关键知识点。 ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • JUC(三):深入解析AQS
    本文详细介绍了Java并发工具包中的核心类AQS(AbstractQueuedSynchronizer),包括其基本概念、数据结构、源码分析及核心方法的实现。 ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • oracle c3p0 dword 60,web_day10 dbcp c3p0 dbutils
    createdatabasemydbcharactersetutf8;alertdatabasemydbcharactersetutf8;1.自定义连接池为了不去经常创建连接和释放 ... [详细]
author-avatar
yuanju1984
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有