当前位置:   article > 正文

多线程(6)- Hook线程与线程异常捕获_易语言hook两种写法冲突咋解决

易语言hook两种写法冲突咋解决


前言

Hook钩子,线程异常
扩展:

概念

  1. UncaughtExceptionHandler: 线程在执行单元(run部分)是不允许抛出异常的,而且线程运行在自己的上下文中,派生它的线程将无法直接获得它运行中出现的异常信息,对此JAVA提供了UncaughtExceptionHandler接口,当线程运行中出现异常,会回调UncaughtExceptionHandler接口,告诉是哪个线程出现什么错误。
  2. Hook钩子:作为程序运行结束时的线程,处理后续工作

1、UncaughtExceptionHandler

API
//特定线程设置全局的UncaughtExceptionHandler 
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
//设置全局的UncaughtExceptionHandler 
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) 
//获取全局的UncaughtExceptionHandler 
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
        return defaultUncaughtExceptionHandler;
    }
//获取特定线程的UncaughtExceptionHandler 
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
dispatchUncaughtException-异常回调
//仅由JVM调用此方法处理异常
/**
     * Dispatch an uncaught exception to the handler. This method is
     * intended to be called only by the JVM.
     */
private void dispatchUncaughtException(Throwable e) {
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、获取线程运行时异常

/**
     * 使用钩子 处理异常
     */
    private static void uncaughtException() {
        Thread.setDefaultUncaughtExceptionHandler((t,e)->{
            System.out.println(t);
            e.printStackTrace();
        });
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(1/0);
        },"thread_uncaught").start();
    }

Thread[thread_uncaught,5,main]
java.lang.ArithmeticException: / by zero
	at com.today.roc.go.understand.thread.six.UncaughtExceptionMain.lambda$main$1(UncaughtExceptionMain.java:28)
	at java.lang.Thread.run(Thread.java:748)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3、异常捕获机制

Thread捕获机制
如果当前线程没有UncaughtExceptionHandler,则线程组处理
  • 1
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }
  • 1
  • 2
  • 3
  • 4
ThreadGroup异常捕获机制
public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
        	//父类不为空,使用父UncaughtExceptionHandler
            parent.uncaughtException(t, e);
        } else {
	        //获取全局UncaughtExceptionHandler
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
            //交给System.err处理
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
异常出现uncaught调用流程:Thread -> ThreadGroup -> MainGroup -> SystemGroup ->System.err
private static void testNoUncaught(){
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        System.out.println(mainGroup);
        System.out.println(mainGroup.getParent());
        System.out.println(mainGroup.getParent().getParent());
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(1/0);
        },"uncaught_thread").start();
    }


java.lang.ThreadGroup[name=main,maxpri=10]
java.lang.ThreadGroup[name=system,maxpri=10]
null
Exception in thread "uncaught_thread" java.lang.ArithmeticException: / by zero
	at com.today.roc.go.understand.thread.six.UncaughtExceptionMain.lambda$testNoUncaught$2(UncaughtExceptionMain.java:51)
	at java.lang.Thread.run(Thread.java:748)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

4、注入钩子线程

当JVM程序停止时,会启动Hook线程,进行事后处理
防止程序重复启动:启动时候创建一个lock文件,添加一个hook当程序停止时删除lock文件,如果文件存在表示程序运行,不能重复启动。
  • 1
  • 2
public class HookMain {

    public static void main(String[] args) {

        Runtime.getRuntime().addShutdownHook(new Thread(
                () -> {
                    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(
                () -> {
                    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.");
                }
        ));

        System.out.println("The program will is stopping");

    }

}

The program will is stopping
The hook thread 2 is running.
The hook thread 1 is running.
The hook thread 2 will exit.
The hook thread 1 will exit.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
防止程序重复启动
/**
     * Hook实战
     */
    public static void hook() throws IOException, InterruptedException {
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.out.println(" program has exit ");
           if (getLookFile().toFile().exists()){
               //删除文件
               getLookFile().toFile().delete();
           }
        }));
        checkRunning();

        IntStream.range(0,5).forEach(v->{
            System.out.println(" the program is running ");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 检查文件是否存在,如果是第一次启动,创建文件
     */
    public static void checkRunning() throws IOException {
        Path path = getLookFile();
        if (path.toFile().exists()) {
            //文件存在,表示已经启动
            throw new RuntimeException("the program already running……");
        }
        Files.createFile(path);
        System.out.println("create file success");
    }

    public static Path getLookFile() {
        return Paths.get(LOCK_PATH, LOCK_FILE);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/265943
推荐阅读
相关标签
  

闽ICP备14008679号