线程三(线程属性 && 线程未捕获异常 && 线程安全问题)

本文详细介绍了Java线程的属性,如ID、名称、守护线程和优先级,以及如何处理线程未捕获异常。重点讲解了守护线程的作用、优先级管理、UncaughtExceptionHandler的使用和线程安全的相关概念,包括上下文切换、线程安全问题和面试题解答。
摘要由CSDN通过智能技术生成

1.线程各属性

属性名称用途
编号(ID)每个线程都有自己的ID,用于标识不同的线程(ID从1开始)
名称(Name)让用户或程序员在开发调试中更容易区分不同线程,定位问题
是否是守护线程(isDaemon)

true(守护线程)/false(非守护线程也称为:“用户线程”)

设置守护线程方法:thread.setDaemon(true)

优先级(Priority)优先级属性目的是告诉调度器用户希望哪些线程多运行,哪些线程少运行(总共10个级别我们创建的线程优先级默认为:5)

1.1.守护线程

        作用:

                 给用户线程提供服务;

        守护线程特性:

                1.线程类型默认继承自父线程(即:守护线程创建出来的线程默认就是守护线程);   

                2.通常守护线程都是由JVM启动的;

                3.不影响JVM退出;

1.2.优先级

          线程优先级总共有10个级别,我们创建出来的线程优先级默认都是5,程序设计不应依赖于优先级,因为不同操作系统优先级不一样且优先级会被操作系统改变,

2.如何处理线程未捕获异常(重要)

        使用“UncaughtExceptionHandler”类来处理未捕获的异常;

2.1.为什么需要UncaughtExceptionHandler?

         因为子线程异常时无法将异常传递给主线程去捕捉(即:子线程异常时主线程使用try-cache捕捉不到);

2.2.演示主线程捕捉不到子线程抛出的异常

/**
 * 演示主线程捕捉不到子线程异常
 */
public class ThreadException implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException("子线程抛出异常");
    }

    public static void main(String[] args) {
        try {
            new Thread(new ThreadException()).start();
        }catch (Exception e){
            System.out.println("主线程捕捉到子线程抛出的异常:" + e);
        }
    }
}

2.3.使用"UncaughtExceptionHandler"实现全局处理子线程异常

import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * 定义未捕获线程异常处理器
 */
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // 日志记录异常原因
        Logger logger = Logger.getAnonymousLogger();
        logger.log(Level.INFO,t.getName() + "异常,被终止啦..");
        logger.log(Level.WARNING,t.getName() + "异常原因:" + e);
    }
}

测试

public class ThreadExcptionMakeOwnUncaughtExceptionHandler implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException("模拟子线程异常");
    }

    public static void main(String[] args) {
        // 设置“未捕获线程异常”处理类
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

        new Thread(new ThreadExcptionMakeOwnUncaughtExceptionHandler(),"线程一").start();
    }
}

3.线程安全

3.1.什么是线程安全?

        业务中多线程同时访问一个对象或方法时我们不需要做额外的处理(像单线程编程一样)程序可以正常运行并能获取到正确的结果(不会因为多线程而出错)我们就认为上面的对象或方法是线程安全的;

3.2.线程安全问题三大类?

        1.运行结果错误;

        2.活跃性问题(死锁、活锁、饥饿);

        3.对象发布和初始化时安全问题;

4.面试题

4.1.守护线程和普通线程区别?

        都是线程整体无区别,唯一区别在于是否能影响到JVM退出,若是用户线程其会响应到JVM的退出(所有用户线程执行完后JVM才会退出),守护线程不会影响到JVM的退出,通常守护线程是由JVM创建的用于执行一些后台任务如“gc垃圾回收”,用户线程是由用户来创建的,守护线程用于给我们创建的用户线程提供服务;

4.2.我们是否需要给线程设置为守护线程?

# 线程设置为守护线程方法
Thread thread = new Thread(...);
thread.setDaemon(true);

        我们不应该把自己的线程设置为守护线程,假如我们的线程设置为“守护线程”当JVM发现没有用户线程时JVM会自动退出,这时我们代码就会被强制关闭,易导致数据不一致问题;

4.3.run()方法是否可以抛出异常?

       run()方法在设计时就没有抛出异常,所以run()方法不能向外抛出异常,我们可以在run()方法内部使用try-cache去捕获处理异常,也可以设置一个全局处理“线程未捕获异常(UncaughtExceptionHandler)”的处理器去处理未捕获线程异常;

4.4.线程中如何处理未捕获的异常?

        使用UncaughtExceptionHandler全局处理未捕获到的线程异常;

4.5.多线程带来性能问题的原因?

        1.上下文切换;

        2.内存同步(单个线程所独占的“本地内存”与所有线程所共享的“主内存”之间的同步(本地内存与主内存同步));

4.6.什么是上下文切换?

        正在运行的线程被其它线程抢占了CPU资源,原本正在运行的线程需要把当前上下文信息(CPU寄存器值,程序计数器等数据)保存到内存中以便下次再次被CPU调度到继续执行,再执行另一个线程的过程叫作上下文切换;

4.7.何时会进行上下文切换?

         1.线程执行时间超过CPU为其分配的时间片;

         2.线程执行了sleep()/wait()方法;

         3.线程IO过程引起的阻塞;

4.8.有哪些线程不安全的情况?

        1.运行结果错误

        2.活跃性问题(死锁、活锁、饥饿)

        3.对象发布和初始化时安全问题

4.9.哪些情况需额外注意线程安全?        

        1.访问共享变量或资源会有并发安全问题比如对象属性、静态变量、共享缓存;

        2.所有依赖时序的操作;(如:原本应该是先写后读,而多线程下可能是先读后写);

        3.不同数据之间存在捆绑关系(如:多个线程间操作应同时成功或同时失败);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值