Java多线程编程7--线程中的异常处理

时间:2021-10-02 18:28:55

1、线程中的异常处理

先看看一个简单的线程异常情况

//有异常的线程
public class MyThread extends Thread {
@Override
public void run() {
String username = null;
System.out.println(username.hashCode());
}
}
public class Run {    public static void main(String[] args) throws InterruptedException {        MyThread t = new MyThread();        t.start();    }}
Exception in thread "Thread-0" java.lang.NullPointerException
    程序运行后在控制台输出空指针异常。在Java的多线程技术中,可以对多线程中的异常进行“捕捉”,使用的是UncaughtExceptionHandler类,从而可以对发生的异常进行有效的处理。
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.setName("线程t1");
t1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("ThreadName="+t.getName()+" 出现了异常");
e.printStackTrace();
}
});
t1.start();
}
}
ThreadName=线程t1 出现了异常
java.lang.NullPointerException
    方法setDefaultUncaughtExceptionHandler()的作用是为指定线程类的所有线程对象设置
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println("ThreadName="+t.getName()+" 出现了异常");
e.printStackTrace();
}
});
MyThread t1 = new MyThread();
t1.setName("线程t1");
t1.start();

MyThread t2 = new MyThread();
t2.setName("线程t2");
t2.start();
}
}
ThreadName=线程t2 出现了异常
java.lang.NullPointerException
ThreadName=线程t1 出现了异常
    at com.changwen.javabase.Thread.base.MyThread.run
java.lang.NullPointerException
---------------------------------------------------------------------------------------------------

2、线程组内的异常处理

public class MyThread extends Thread {
private String num;

public MyThread(ThreadGroup group, String name,String num) {
super(group, name);
this.num = num;
}

@Override
public void run() {
try {
int numInt = Integer.parseInt(num);

while (true) {
Thread.sleep(3000); //防止运行太快,看不到想要结果
System.out.println("死循环中:" + Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {    public static void main(String[] args) throws InterruptedException {        ThreadGroup group = new ThreadGroup("我的线程组");        MyThread[] myThreads = new MyThread[10];        for (int i=0; i<myThreads.length; i++) {            myThreads[i] = new MyThread(group, "线程"+(i+1), "1");            myThreads[i].start();        }        MyThread newThread= new MyThread(group,"报错线程", "a");        newThread.start();    }}
Exception in thread "报错线程" java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.parseInt(Integer.java:499)
死循环中:线程2
死循环中:线程6
死循环中:线程1
死循环中:线程5
死循环中:线程9
死循环中:线程7
    程序运行后,其中一个线程出现异常,但其他线程却一直以死循环的方式持续打印结果
    从运行的结果来看,在默认的情况下,线程组中的一个线程出现异常不会影响其他线程的运行。
    如果想实现线程组内一个线程出现异常后全部线程都停止该如何实现呢?

public class MyThreadGroup extends ThreadGroup {

public MyThreadGroup(String name) {
super(name);
}

//参数t是出现异常的线程对象
@Override
public void uncaughtException(Thread t, Throwable e) {
super.uncaughtException(t, e);
this.interrupt();
}
}
public class MyThread extends Thread {    private String num;    public MyThread(ThreadGroup group, String name,String num) {        super(group, name);        this.num = num;    }    /**     * 需要注意的是,使用自定义java.lang.ThreadGroup线程组,     * 并且重写uncaughtException方法处理组内线程中断行为时,     * 每个线程对象中的run()方法内部不要有异常catch语句,     * 如果有catch语句,则     * public void uncaughtException(Thread t, Throwable e)不执行     */    @Override    public void run() {        int numInt = Integer.parseInt(num);        while (this.isInterrupted() == false) {            System.out.println("死循环中:" + Thread.currentThread().getName());        }    }}
public class Run {    public static void main(String[] args) throws InterruptedException {//        ThreadGroup group = new ThreadGroup("我的线程组");        MyThreadGroup group = new MyThreadGroup("我的线程组");        MyThread[] myThreads = new MyThread[10];        for (int i=0; i<myThreads.length; i++) {            myThreads[i] = new MyThread(group, "线程"+(i+1), "1");            myThreads[i].start();        }        MyThread newThread= new MyThread(group,"报错线程", "a");        newThread.start();    }}

死循环中:线程10
死循环中:线程5
死循环中:线程1
死循环中:线程6
死循环中:线程7
Exception in thread "报错线程" java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.parseInt(Integer.java:499)
    程序运行后,其中一个线程出现异常,其他线程全部停止了。
3、线程异常处理的传递
    前面介绍了若干个线程异常处理的方式,那么这些处理的方式如果放在一起运行,会出现什么样的运行结果?
public class MyThread extends Thread {
private String num = "a";

public MyThread() {
super();
}

public MyThread(ThreadGroup group, String name) {
super(group, name);
}

@Override
public void run() {
int numInt = Integer.parseInt(num);
System.out.println("在线程中打印:" +(numInt+1));
}
}
public class MyThreadGroup extends ThreadGroup {    public MyThreadGroup(String name) {        super(name);    }    //参数t是出现异常的线程对象    @Override    public void uncaughtException(Thread t, Throwable e) {        super.uncaughtException(t, e);        System.out.println("线程组的异常处理");        e.printStackTrace();    }}
public class ObjectUncaughtExceptionHandler        implements UncaughtExceptionHandler {    public void uncaughtException(Thread t, Throwable e) {        System.out.println("对象的异常处理");        e.printStackTrace();    }}
import java.lang.Thread.UncaughtExceptionHandler;public class StateUncaughtExceptionHandler implements UncaughtExceptionHandler {    public void uncaughtException(Thread t, Throwable e) {        System.out.println("静态的异常处理");        e.printStackTrace();    }}
public class Run {    public static void main(String[] args) throws InterruptedException {        MyThread myThread = new MyThread();        //对象        myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());        //类        MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());        myThread.start();    }}
对象的异常处理
java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.parseInt(Integer.java:499)


修改Run类如下:

public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();

//对象
// myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
//类
MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());

myThread.start();
}
}
静态的异常处理
java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.parseInt(Integer.java:499)

继续修改:

public class Run {
public static void main(String[] args) throws InterruptedException {
MyThreadGroup group = new MyThreadGroup("我的线程组");
MyThread myThread = new MyThread(group, "我的线程");

//对象
myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());
//类
MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());

myThread.start();
}
}
对象的异常处理
java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:449)
    at java.lang.Integer.parseInt(Integer.java:499)