Day277.线程的各个属性多线程未捕获异常处理 -Juc
Posted 阿昌喜欢吃黄桃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day277.线程的各个属性多线程未捕获异常处理 -Juc相关的知识,希望对你有一定的参考价值。
①线程的各个属性
一、学习前思考的问题
- 什么时候我们需要设置守护线程?
- 应该如何应用线程优先级来帮助线程运行?有哪些禁忌?
- 不同操作系统如何处理优先级问题?
二、线程各属性纵览
三、线程ID
- 每个线程都有id,这个id不能修改
- 线程id会不停的自增,从1开始
- main函数就是第一个线程
- id是操作系统用来识别各个线程的编号
/******
@author 阿昌
@create 2021-05-24 20:26
*******
* 线程Id从1开始,JVM运行起来后,自己创建的线程的Id早已不是0
*/
public class Id {
public static void main(String[] args) {
Thread thread = new Thread();
System.out.println("主线程Id:"+Thread.currentThread().getId());
System.out.println("子线程Id:"+thread.getId());
}
}
以上看到主线程的id为1,可以理解,那么为什么我们创建的子线程id就直接为12了???
我们打断点调试发现,JVM其实已经为我们创建了许多线程↓↓↓
四、线程名字
1、默认线程名的源码分析
- 有参构造器,指定线程名
- 无参构造器,默认为
Thread-
,加上nextThreadNum,这个数字为0开始,自增
2、修改线程的名字
也就是说在线程没有启动之前,我们可以调用setName()方法去设置线程的名字,不然就是调用setNativeName(name),在C/C++层面去设置线程的默认名字,也就是我们上面的默认名字
五、守护线程
作用: 给用户线程提供服务
分类的标准: 看这个线程是否会阻止JVM的停止
特性:
- 线程类型默认
继承
自父线程 被谁
启动不影响
JVM退出
守护线程和普通线程的区别:
- 整体
无
区别 唯一
的区别在于是否影响JVM离开- 守护线程不会影响,JVM检测到用户线程全部执行完毕,就会关闭
- 用户线程会影响,用户线程没执行完,JVM不会关闭
六、线程优先级
- 10个优先级,
默认为5
- 程序的设计不应该依赖于优先级
- 不同的
操作系统优先级不同
window
中只有7个优先级linux
中所有线程优先级会被忽略,所有线程优先级一致
- 优先级会被操作系统修改
- 不同的
总结:
我们只需要了解线程有优先级的概念,优先级越大越优先即可,不需要去修改优先级
七、各属性总结
八、面试常见问题
1、守护线程和普通线程的区别?
-
整体上没有太大区别
-
区别在于,是否
影响JVM
退出 -
用户线程执行逻辑,守护线程是服务于用户线程
2、是否需要人为的设置守护线程?
我们不应该人为的将我们的线程设置为守护线程;
会出现数据不一致
的问题
3、什么时候我们需要设置守护线程?
通常情况下JVM的守护线程足够我们使用,我们不需要设置守护线程
4、如果应用线程优先级来帮助程序运行?有哪些禁忌?
我们不应该通过程序优先级来帮助程序运行,线程优先级与操作系统息息相关,他会受到各个操作系统的影响,不容易实现控制,所以不推荐使用
②线程未异常处理
一、学习前的思考
- Java异常体系图
- 实际工作中,如何全局处理异常?为什么要全局处理?不处理行不行?
二、线程未捕获异常UncaughtException应该如何处理
1、为什么需要UncaughtExceptionHandler?
1)主线程可轻松的发现异常,子线程却不行
子线程发生异常,不影响主线程,不会终止主线程的程序,主线程将继续执行
/******
@author 阿昌
@create 2021-05-24 21:12
*******
* 单线程,抛出,处理异常堆栈
* 多线程,子线程发生异常,会有什么不同???
* 子线程发生异常,不影响主线程,不会终止主线程的程序,主线程将继续执行
*/
public class ExceptionInChildThread implements Runnable {
@Override
public void run() {
throw new RuntimeException();
}
//主线程
public static void main(String[] args) {
new Thread(new ExceptionInChildThread()).start();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
2)子线程异常无法用传统异常捕获方式捕获
- 不加try-catch 抛出4个异常,都带线程名
public class CantCatchDirectly implements Runnable {
@Override
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
new Thread(new CantCatchDirectly(),"线程1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程4").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程5").start();
}
}
- 加了try-catch,期望捕获第一个线程的异常。线程234不应该运行,希望看到控制台打印异常信息Caught Exception
public class CantCatchDirectly implements Runnable {
@Override
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
try {
new Thread(new CantCatchDirectly(),"线程1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程4").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程5").start();
} catch (RuntimeException e) {
System.out.println("抓住异常");
e.printStackTrace();
}
}
}
发现异常根本抓不住!!!!!!!!!
因为try-catch只能捕获到对应线程内的异常,他try-catch的是主线程的,而异常是发现在子线程中
3)不能直接捕获的后果、提高健壮性
2、两种解决方案
1)方案一:手动在每个run方法里进行try-catch(不推荐)
public class CantCatchDirectly implements Runnable {
@Override
public void run() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println("捕获异常");
}
}
public static void main(String[] args) throws InterruptedException {
new Thread(new CantCatchDirectly(),"线程1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程4").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"线程5").start();
}
}
2)方案二:利用UncaughtExceptionHandler(推荐)
- UncaughtExceptionHandler接口
- void uncaughtException(Thread t,Throwable e);
- 异常处理器的
调用策略
- 自定义UncaughtExceptionHanlder
/******
@author 阿昌
@create 2021-05-24 21:40
*******
* 自定义 UncaughtExceptionHandler
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
private String name;
public MyUncaughtExceptionHandler(String name) {
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.WARNING,"线程异常:"+t.getName(),e);
System.out.println(name+"我捕获了异常"+t.getName()+"异常名字:"+e);
}
}
- 使用自定义 UncaughtExceptionHandler
/******
@author 阿昌
@create 2021-05-24 21:44
*******
* 使用自定义的 UncaughtExceptionHandler
*/
public class UseMyUncaughtExceptionHandler implements Runnable {
@Override
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
//设置自定义异常处理器
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("我们自定义的线程异常处理器"));
new Thread(new UseMyUncaughtExceptionHandler(),"线程1").start();
Thread.sleep(300);
new Thread(new UseMyUncaughtExceptionHandler(),"线程2").start();
Thread.sleep(300);
new Thread(new UseMyUncaughtExceptionHandler(),"线程3").start();
Thread.sleep(300);
new Thread(new UseMyUncaughtExceptionHandler(),"线程4").start();
Thread.sleep(300);
new Thread(new UseMyUncaughtExceptionHandler(),"线程5").start();
}
}
三、线程的未捕获异常—常见面试题
1、Java异常体系是什么?
2、如何处理全局异常?为什么要全局异常处理?不处理行不行?
通过实现一个全局的UncaughtExceptionHandler接口
;
打印日志方便我们后期的维护,给前端统一的返回;
不处理不行
3、run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?
不可以抛出异常,只能自己处理try-catch;
线程状态会获取到异常,并终止程序
4、线程中如何处理某个未处理异常?
通过实现一个全局的UncaughtExceptionHandler接口
;
以上是关于Day277.线程的各个属性多线程未捕获异常处理 -Juc的主要内容,如果未能解决你的问题,请参考以下文章
当其中一个线程中存在未捕获的异常时,Python 多线程程序不会退出