Java多线程--全局异常处理--方法实例

Java多线程--全局异常处理--方法实例,第1张

Java多线程--全局异常处理--方法/实例

原文网址:Java多线程--全局异常处理--方法/实例_IT利刃出鞘的博客-CSDN博客

简介

说明

        本文用示例介绍如何全局捕获处理Java多线程中的异常。

        在Java中,线程中的异常是不能抛出到调用该线程的外部方法中捕获的,只能在线程内部进行捕获。

为什么不能抛出异常到外部线程捕获?

        因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。基于这样的设计理念,在Java中,线程方法的异常都应该在线程代码边界之内(run方法内)进行处理。换句话说,我们不能捕获从线程中逃逸的异常。

JDK如何控制线程异常不会跑到外部线程?

通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。

如果在线程中抛出异常线程会怎么样?

线程会立即终结。

如何捕获线程中的异常?

法1:使用try-catch-finally来包含代码块

法2:使用全局异常处理 UncaughtExceptionHandler
        UncaughtExceptionHandler能检测出某个线程由于未捕获的异常而终结的情况。当一个线程由于未捕获异常而退出时,JVM会把这个事件报告给应用程序提供的UncaughtExceptionHandler异常处理器(这是Thread类中的接口):

public interface UncaughtExceptionHanlder {
	void uncaughtException(Thread t, Throwable e);
}

        JDK5之后可以在每一个Thread对象上添加一个异常处理器UncaughtExceptionHandler 。Thread.UncaughtExceptionHandler.uncaughtException()方法会在线程因未捕获的异常而面临死亡时被调用。

实例:不捕获异常
package com.example.a;

class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + ":运行开始");
        int i = 1 / 0;
        System.out.println(name + ":运行结束");
    }
}

public class Demo {
    public static void main(String[] args) {
        System.out.println("主线程开始");
        Thread thread = new Thread(new MyThread("线程1"));
        thread.start();
        System.out.println("主线程结束");
    }
}

执行结果

主线程开始
主线程结束
线程1:运行开始
Exception in thread "Thread-1" java.lang.ArithmeticException: / by zero
	at com.example.a.MyThread.run(Demo.java:13)
	at java.lang.Thread.run(Thread.java:748)
全局异常处理

        本处只展示全局异常处理的方案。在线程代码里边加try catch这种方法就不贴出了,很基础。

        法1,2,3也同样适用于Runnable方式创建的线程,比如:Thread thread = new Thread(new MyRunnable("线程1"));

法1:handler
package com.example.a;

class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + ":运行开始");
        int i = 1 / 0;
        System.out.println(name + ":运行结束");
    }
}

class MyUncheckedExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕获到异常。异常栈信息为:");
        e.printStackTrace();
    }
}

public class Demo {
    public static void main(String[] args) {
        System.out.println("主线程开始");
        Thread thread = new Thread(new MyThread("线程1"));
        thread.setUncaughtExceptionHandler(new MyUncheckedExceptionHandler());
        thread.start();
        System.out.println("主线程结束");
    }
}

执行结果

主线程开始
主线程结束
线程1:运行开始
捕获到异常。异常栈信息为:
java.lang.ArithmeticException: / by zero
	at com.example.a.MyThread.run(Demo.java:13)
	at java.lang.Thread.run(Thread.java:748)
法2:线程组
package com.example.a;

public class Demo {
    public static void main(String[] args) {
        System.out.println("主线程开始");

        ThreadGroup threadGroup = new ThreadGroup("MyGroup") {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("捕获到异常。异常栈信息为:");
                e.printStackTrace();
            }
        };

        Thread thread = new Thread(threadGroup, new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程运行开始");
                int i = 1 / 0;
                System.out.println("子线程运行结束");
            }
        });

        thread.start();
        
        System.out.println("主线程结束");
    }
}

运行结果

主线程开始
主线程结束
子线程运行开始
捕获到异常。异常栈信息为:
java.lang.ArithmeticException: / by zero
	at com.example.a.Demo.run(Demo.java:19)
	at java.lang.Thread.run(Thread.java:748)
法3:默认的handler

        如果只需要一个线程异常处理器处理线程的异常,那么我们可以设置一个默认的线程异常处理器,当线程出现异常时,
        如果没有指定线程的异常处理器,而且线程组也没有设置,那么就会使用默认的线程异常处理器

package com.example.a;

class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + ":运行开始");
        int i = 1 / 0;
        System.out.println(name + ":运行结束");
    }
}

class MyUncheckedExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕获到异常。异常栈信息为:");
        e.printStackTrace();
    }
}

public class Demo {
    public static void main(String[] args) {
        System.out.println("主线程开始");
        Thread.setDefaultUncaughtExceptionHandler(new MyUncheckedExceptionHandler());
        Thread thread = new Thread(new MyThread("线程1"));
        thread.start();
        System.out.println("主线程结束");
    }
}

执行结果

主线程开始
主线程结束
线程1:运行开始
捕获到异常。异常栈信息为:
java.lang.ArithmeticException: / by zero
	at com.example.a.MyThread.run(Demo.java:13)
	at java.lang.Thread.run(Thread.java:748)
法4:FutureTask

上面说的3种方法都是基于线程异常处理器实现的,本方法不需要线程异常处理器。

package com.example.a;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo {
    public static void main(String[] args) {
        System.out.println("主线程开始");

        //1.创建FeatureTask
        FutureTask futureTask = new FutureTask<>(new Callable() {
            @Override
            public Integer call() throws Exception {
                System.out.println("子线程运行开始");
                return 1 / 0;
            }
        });

        //2.创建Thread
        Thread thread = new Thread(futureTask);
        
        //3.启动线程
        thread.start();

        try {
            Integer result = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            //4.处理捕获的线程异常
            System.out.println("捕获到异常。异常栈信息为:");
            e.printStackTrace();
        }

        System.out.println("主线程结束");

    }
}

执行结果

主线程开始
子线程运行开始
捕获到异常。异常栈信息为:
主线程结束
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:192)
	at com.example.a.Demo.main(Demo.java:27)
Caused by: java.lang.ArithmeticException: / by zero
	at com.example.a.Demo.call(Demo.java:16)
	at com.example.a.Demo.call(Demo.java:12)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.lang.Thread.run(Thread.java:748)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5079002.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-16
下一篇 2022-11-16

发表评论

登录后才能评论

评论列表(0条)

保存