当单线程中初出现异常时,我们可在该线程run()方法的catch语句中进行处理,当有多个线程中出现异常时,我们就得在每个线程run()方法的catch语句中进行处理,这样会造成代码严重冗余。我们可以使用setDefaultUncaoughtExceptionHandler()
和方法setUncaughtExceptionHandler()
方法来集中处理线程的异常。
public class Main{
public static void main(String[] args) {
MyThread t=new MyThread();
t.start();
}
}
class MyThread extends Thread{
@Override
public void run(){
String username=null;
System.out.println(username.hashCode());
}
}
如上面的程序,程序运行后,控制台输出空指针异常。在java的多线程技术中,我们可以对多线程中的异常进行捕获,使用的是UncaughtExceptionHandler
接口。从而对异常进行有效处理。当线程出现异常而终止时,JVM虚拟机捕获到此情况,并自动调用UncaughtExceptionHandler
接口中的void uncaughtException(Thread t,Throwable e)
方法来处理异常,使对多个线程的异常处理更集中。
public class Main{
public static void main(String[] args) {
MyThread t=new MyThread();
t.setName("线程t");
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程:"+t.getName()+"出现了异常");
}
});
t.start();
MyThread t2=new MyThread();
t2.setName("线程t2");
t2.start();
}
}
class MyThread extends Thread{
@Override
public void run(){
String username=null;
System.out.println(username.hashCode());
}
}
setUncaughtExceptionHandler
方法的作用是对指定的线程对象设置默认的异常处理器。在Thread类中,我们还可以使用setDefaultUncaoughtExceptionHandler
方法对所有的线程设置异常处理器
public class Main{
public static void main(String[] args) {
MyThread t=new MyThread();
t.setName("线程t");
MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程:"+t.getName()+"出现了异常");
e.printStackTrace();
}
});
t.start();
MyThread t2=new MyThread();
t2.setName("线程t2");
t2.start();
}
}
class MyThread extends Thread{
@Override
public void run(){
String username=null;
System.out.println(username.hashCode());
}
}
可以对所有的线程都生效了
Java中的线程组(ThreadGroup)用于将一组线程组织在一起,并提供一些管理和操作的功能。然而,线程组在现代的Java编程中已经不常使用,并且在Java 9中已被标记为过时(deprecated)。尽管如此,我们可以描述一下线程组可能出现的异常情况和行为。以下是一些可能与线程组相关的异常:
IllegalThreadStateException(非法线程状态异常):当尝试将一个线程添加到已经销毁的线程组或一个线程组已经被终止时,可能会抛出此异常。
SecurityException(安全异常):在某些安全受限的环境中,如果没有足够的权限创建或修改线程组,可能会抛出此异常。
NullPointerException(空指针异常):在某些情况下,尝试对一个空的线程组对象进行操作(如添加线程、设置线程组名称等)可能会导致此异常。
需要注意的是,由于线程组在现代Java编程中已经不常用,因此在实际开发中可能很少会遇到与线程组相关的异常。为了更好地管理和组织线程,推荐使用更高级别的并发工具,如线程池(ThreadPoolExecutor)和并发集合(ConcurrentHashMap、ConcurrentLinkedQueue等)。
public class Main{
public static void main(String[] args) {
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 newT=new MyThread(group,"报错线程","aasdfsdf");
newT.start();
}
}
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(){
int minINt=Integer.parseInt(num);
while(true){
System.out.println("死循环中:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
程序运行后其中一个线程出现了异常,而其它线程一直以死循环的方式持续打印结果。从运行结果来看,默认情况下线程组中的一个线程出现异常后不会影响其他线程的运行。见下面代码:
public class Main{
public static void main(String[] args) {
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 newT=new MyThread(group,"报错线程","aasdfsdf");
newT.start();
}
}
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(){
int minINt=Integer.parseInt(num);
while(this.isInterrupted()==false){
System.out.println("死循环中:"+Thread.currentThread().getName());
}
}
}
class MyThreadGroup extends ThreadGroup{
public MyThreadGroup(String name){
super(name);
}
@Override
public void uncaughtException(Thread t,Throwable e){
super.uncaughtException(t,e);
this.interrupt();
}
}
可见发现所有的线程都停止了。这里使用自定义的线程组,并重写了
uncaughtException
,当线程出现异常时调用interrupt方法,终止所有线程。