JAVA基础知识之多线程——线程组和未处理异常

时间:2022-09-22 20:52:56

线程组

Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组。

线程组具有以下特征

如果没有显式指定线程组,则新线程属于默认线程组,默认情况下,与创建线程所在的组相同

一旦确定了线程所在线程组之后,不允许更改线程组,直到线程死亡

对于线程组ThreadGroup的一个对象,就表示一个线程组,线程组通过ThreadGroup(group...)来初始化,

线程组可以通过interrput(), setDamemon(),setMaxPriority()等方法来操作组内线程,通过activeCount(),isDamemon()来获取线程信息

下面是一个例子,

 package threads;

 public class MyThread extends Thread {
public MyThread(String name) {
super(name);
} public MyThread(ThreadGroup group, String name) {
super(group,name);
} public void run() {
for (int i = 0; i<10; i++) {
System.out.println(getName() + " 线程的i变量 " + i);
}
}
}
 package threads;

 public class ThreadGroupTest {
public static void main(String[] args) {
//获取主线程所在的线程组,这是所有线程默认的线程组
ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
System.out.println("主线程组的名字: "+mainGroup.getName());
System.out.println("主线程组是否为后台线程组: "+ mainGroup.isDaemon());
new MyThread("主线程组的线程").start();
ThreadGroup tg = new ThreadGroup("新线程组");
tg.setDaemon(true);
MyThread tt = new MyThread(tg, "tg线程组的线程甲");
tt.start();
new Thread(tg,"tg线程组的线程乙").start();
}
}

未处理异常

JAVA5之后,JVM会在线程抛出未处理异常后自动查找是否有对应的“未处理异常”处理对象,即Thread.UncaughtExceptionHandler对象,如果找到了该处理器对象,就会调用对象的uncaughtException来处理异常。

Thread提供了两个方法来自定义(未处理的)异常处理,

setDefaultUncaughtExceptionHandler(eh), 为线程类的所有实例设置默认的异常处理器

setUncaughtExceptionHandler(eh),为指定线程实例设置异常处理器

而在线程组中,因为ThreadGroup类也实现了Thread.UncaughtExceptionHandler接口,所以线程组会成为默认的异常处理器。

线程组处理异常的流程如下,

  • 如果该线程组有父线程组,则调用父线程组的uncaughtException方法来处理异常
  • 如果线程类有默认异常处理器,则用该异常处理器处理异常
  • 如果异常对象不是ThreadDeath,就会打印异常信息,并结束该线程

下面演示一个例子,为主线程设置一个默认的异常处理器,当主程序抛出一个未处理异常时,该异常处理器将会起作用。

当一个线程抛出一个未处理异常时,JVM首先会查找该异常对应的异常处理器,

 package threads;

 //自定义异常处理器,只需要实现Thread.UncaughtExceptionHandler接口
public class MyExHandler implements Thread.UncaughtExceptionHandler { //uncaughtException方法将处理线程中未处理的异常
@Override
public void uncaughtException(Thread t, Throwable e) {
// TODO Auto-generated method stub
System.out.println("自定义异常处理: "+ t + " 线程出现了异常 " + e);
}
}
 package threads;

 public class ExHandler {
public static void main(String[] args) {
//设置主线程的默认异常处理器
Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
int a = 5/0;
System.out.println("程序正常结束");
}
}

执行结果,可以看到程序虽然用自定义的异常处理器处理了一个未处理的异常,但还是没有正常结束程序,而是在处理完异常后直接结束了程序。

 自定义异常处理: Thread[main,5,main] 线程出现了异常 java.lang.ArithmeticException: divide by zero

如果注释掉主程序中的第6行,让JVM来处理未处理的异常,执行结果如下,也是不能正常结束程序

 Exception in thread "main" java.lang.ArithmeticException: divide by zero
at threads.ExHandler.main(ExHandler.java:7)

如果使用try catch finally来处理, 修改主程序如下,

 package threads;

 public class ExHandler {
public static void main(String[] args) {
//设置主线程的默认异常处理器
//Thread.currentThread().setUncaughtExceptionHandler(new MyExHandler());
try {
int a = 5/0;
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("程序正常结束");
}
}
}

执行结果如下,可以看到这时候程序可以正常结束了,说明用try catch处理异常时,异常不会向上传给调用者

 java.lang.ArithmeticException: divide by zero程序正常结束

     at threads.ExHandler.main(ExHandler.java:8)

以下引用自 阿里巴巴Java开发手册

9. 【强制】多线程并行处理定时任务时,Timer运行多个TimeTask 时,只要其中之一没有捕获

抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。

JAVA基础知识之多线程——线程组和未处理异常的更多相关文章

  1. JAVA基础知识之多线程——线程池

    线程池概念 操作系统或者JVM创建一个线程以及销毁一个线程都需要消耗CPU资源,如果创建或者销毁线程的消耗源远远小于执行一个线程的消耗,则可以忽略不计,但是基本相等或者大于执行线程的消耗,而且需要创建 ...

  2. JAVA基础知识之多线程——线程通信

    传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...

  3. JAVA基础知识之多线程——线程同步

    线程安全问题 多个线程同时访问同一资源的时候有可能会出现信息不一致的情况,这是线程安全问题,下面是一个例子, Account.class , 定义一个Account模型 package threads ...

  4. JAVA基础知识之多线程——线程的生命周期(状态)

    线程有五个状态,分别是新建(New).就绪(Runnable).运行(Running).阻塞(Blocked)和死亡(Dead). 新建和就绪 程序使用new会新建一个线程,new出的对象跟普通对象一 ...

  5. java基础知识总结--多线程

    1.扩展Java.lang.Thread类 1.1.进程和线程的区别: 进程:每个进程都有自己独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1~n个线程. 线程:同一类线 ...

  6. Java基础&lowbar;死锁、线程组、定时器Timer

    一.死锁问题: 死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. 比如,线程一需要第一把所,此时锁处于空闲状态,给了 ...

  7. JAVA基础知识之多线程——控制线程

    join线程 在某个线程中调用其他线程的join()方法,就会使当前线程进入阻塞状态,直到被join线程执行完为止.join方法类似于wait, 通常会在主线程中调用别的线程的join方法,这样可以保 ...

  8. Java基础知识(多线程和线程池)

    新建状态: 一个新产生的线程从新状态开始了它的生命周期.它保持这个状态直到程序 start 这个线程. 运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为 ...

  9. JAVA基础知识之多线程——三种实现多线程的方法及区别

    所有JAVA线程都必须是Thread或其子类的实例. 继承Thread类创建线程 步骤如下, 定义Thead子类并实现run()方法,run()是线程执行体 创建此子类实例对象,即创建了线程对象 调用 ...

随机推荐

  1. PHP的性能大坑--strtotime函数

    最近在做一个游戏数据统计后台,最基础的功能是通过分析注册登录日志来展示用户数据.在公司内部测试,用户量很少,所以就没有发现什么性能问题.但是这两天一起放到真实的测试环境,用户量噌噌地就涌进来了,从下午 ...

  2. mov和ldr&sol;str的区别

    ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令.比如想把数据从内存中某处读取到寄存器中,只能使用ldr比如:ldr r0, 0x12345678就 ...

  3. ajax实现文件下载

    前台: <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> ...

  4. vim常用指令及快捷键(持续更新)

    (这些文章都是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) 发现了个非常赞的网站  http://openvim.com/ 以下很多操作都是安装好vund ...

  5. Js制作点击输入框时默认文字消失的效果

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-02-17) 为了提高用户体验和易用度,一些设计师会对网页中用户经常用的东西进行优化,比如输入框.一般的输入框是怎样优化的呢 ...

  6. 导航条上UIBarButtonItem的更改方法(使用initWithCustomView&colon;btn)

    UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:self.newMe ...

  7. Git超实用总结,再也不怕记忆力不好了

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯工蜂发表于云+社区专栏 Git 是什么? Git 是一个分布式的代码管理容器,本地和远端都保有一份相同的代码. Git 仓库主要是 ...

  8. 第30章:MongoDB-索引--地理信息索引

    ①地理信息索引 地理信息索引分为两类:2D平面索引,另外就是2DSphere球面索引.在2D索引里面基本上能够保存的信息都是坐标,而且坐标保存的就是经纬度坐标. 范例:定义一个商铺的集合 db.sho ...

  9. &lbrack;leetcode trie&rsqb;208&period; Implement Trie &lpar;Prefix Tree&rpar;

    实现一个字典树 class Trie(object): def __init__(self): self.root = TrieNode() def insert(self, word): cur = ...

  10. VMware中Linux启动时&ast;&ast;&ast;Host SMBus controller not enabled的解决方法

    Ubuntu18.04 64位 1.1如果能进入图形界面 在终端输入sudo su 键入root密码 //切换到root用户 1.2 如果不能进入图形界面,在VMware进入界面时按下shift进入G ...