Java线程深入学习(五)

目录

第六章、线程管理

6.1 线程组

6.1.1 创建线程组

6.2.2 线程组的基本操作

6.2 捕获线程的执行异常

6.3 注入Hook钩子线程

6.4 线程池

6.4.1 什么是线程池

6.4.2 JDK对线程池的支持

6.4.3 核心线程池的底层实现

6.4.4 拒绝策略

6.4.5 ThreadFactory线程工厂

6.4.6 监控线程池

6.4.7 扩展线程池

6.4.8 优化线程池大小

6.4.9 线程池死锁

6.4.10 线程池中的异常处理

6.4.11 ForkJoinPool线程池


第六章、线程管理

6.1 线程组

   类似于在计算机中使用文件夹管理文件,也可以使用线程组来管理线程。在线程祖中定义一组相似(相关)的线程,在线程组中也可以定义子线程组。

   Thread类有几个构造方法允许在创建线程时指定线程组,如果在创建线程时没有指定线程组则该线程就属于父线程所在的线程组。JVM在创建main线程时会为它指定一个线程组,因此每个java线程都有一个线程组与之关联,可以调用线程的getThreadGroup()方法返回线程组。

   线程组开始是处于安全的考虑设计用来区分不同的Applet,然而ThreadGroup并未实现这一目标,在新开发的系统中,已经不常用线程组,现在一般会将一组相关的线程存入一个数组或一个集合中,如果仅仅是用来区分线程时,可以使用线程名来区分,多数情况下,可以忽略线程组。

   main线程组的父线程组是system

   线程组也是它自己的父线程组。

6.1.1 创建线程组

   类java.lang.ThreadGroup

   构造方法

        ①ThreadGroup(String name);

        ②ThreadGroup(ThreadGroup parent, String name);

public class Test {
    public static void main(String[] args) throws InterruptedException {
        //返回当前main线程的线程组
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        System.out.println(mainGroup);

        //定义线程组,如果不指定所属线程组,则自定归属当前线程所属的线程组中
        ThreadGroup group1 = new ThreadGroup("group1");
        System.out.println(group1);

        //创建一个线程组,同时指定父线程组
        ThreadGroup group2 = new ThreadGroup(mainGroup,"group2");
        //现在group1与group2都是mainGroup线程组中的子线程组
        System.out.println(group1.getParent() == mainGroup);//getParent()方法返回父线程组
        System.out.println(group2.getParent() == mainGroup);

        //在创建线程时指定所属线程组
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread());
            }
        };
        //在创建线程时,如果没有指定线程组,则默认线程归属到父线程的线程组中(此时的父线程就是main线程)
        Thread t1= new Thread(r,"t1");
        System.out.println(t1);//Thread[t1,5,main] t1的线程组是main线程组
        //指定线程所属的线程组
        Thread t2 = new Thread(group1,r,"t2");
        System.out.println(t2);//Thread[t2,5,group1]
    }
}

6.2.2 线程组的基本操作

   int activeCount();   返回当前线程组及子线程组中活动线程的数量(近似值)。

   int activeGroupCount();   返回当前线程组及子线程组中活动线程组的数量(近似值)。

   int enumerate(Thread[] list, boolean recurse);   把当前线程组和子线程组中所有的线程复制到参数数组中。

   int enumerate(Thread[] list, boolean recurse);   如果第二个参数设置为false,则只复制当前线程组中所有的线程,不复制子线程组中的线程。

   int enumerate(ThreadGroup[] list);   将当前线程组和子线程组中所有的活动线程组复制到参数数组中。

   int enumerate(ThreadGroup[] list, boolean recurse);   第二个参数设置为false,则只复制当前线程组的子线程组,不复制子线程组中的线程组。

   getMaxPriority();   返回线程组的最大优先级,默认是10。

   getName();   返回线程组的名称。

   getParent();   返回父线程组。

   interrupt();   中断线程组中所有的线程。可以给该线程组中所有的活动线程添加中断标志。

   isDaemon();   判断当前线程是否为守护线程组。

   list();   将当前线程中的活动线程打印出来。

   parebtOf(ThreadGroup g);   判断当前线程组是否为参数线程组的父线程组。

   setDaemon(boolean daemon);   将参数设置为true,就可以把当前线程组设置为守护线程组。当守护线程中没有任何活动线程时,守护线程组会自动销毁。注意线程组的守护属性,不影响线程组中线程的守护属性,或者说守护线程组中的线程可以是非守护线程

6.2 捕获线程的执行异常

   在线程的run方法中,如果有受检异常(编译时异常)必须进行捕获处理,如果想要获得run()方法中出现的非受检异常(运行时异常),可以通过UncaughtExceptionHandler接口获得哪个线程出现了运行时异常。在Thread类中有关处理运行异常的方法有:

        ①getDefaultUncaughtExceptionHandler()   获得全局的(默认的)UncaughtExceptionHandler,

          是一个静态方法

        ②setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)   设置全局

          的UncaughtExceptionHandler,是一个静态方法

        ②getUncaughtExceptionHandler()   获得当前线程的UncaughtExceptionHandler,是一个实

          例方法。

        ③setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)   设置当前线程的

          UncaughtExceptionHandler,是一个实例方法。

   在线程运行过程中出现异常,JVM(也只有JVM可以调用)会调用Thread类的dispatchUncaughtException(Throwable e)方法,该方法会调用getUncaughtExceptionHandler().uncaughtException(this,e); 如果想要获得线程中出现异常的信息,就需要设置线程的UncaughtExceptionHandle。

//演示设置线程的UncaughtExceptionHandler接口
public class Test {
    public static void main(String[] args) throws InterruptedException {
        //1.设置线程的全局的回调接口
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                //t参数接收发生异常的线程,e就是该线程中的异常
                System.out.println(t.getName() + "线程产生了异常:" + e.getMessage());
            }
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "开始运行");
                try {
                    Thread.sleep(2000);//受检异常必须捕获处理
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(12 / 0);//会产生算术异常
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                String txt = null;
                System.out.println(txt.length());//会产生空指针异常
            }
        }).start();

        /*
            在实际开发中,这种设计异常处理的方式还是比较常用的,尤其是异常执行的方法。
            如果线程产生了异常,JVM会调用dispatchUncaughtException()方法,在该方法中调用了getUncaughtExceptionHandler().uncaughtException(this, e);
            如果当前线程设置了UncaughtExceptionHandler回调接口就直接调用它自己的uncaughtException方法;
            如果没有设置则调用当前线程所在线程组的UncaughtExceptionHandler回调接口的uncaughtException方法;
            如果线程组也没有设置该回调接口,则直接把异常的栈信息定向到System.err中。
         */
    }
}

6.3 注入Hook钩子线程

   现在很多软件包括MySQL、Zookeeper、kafka等都存在Hook线程的校验机制,目的是校验进程是否已启动,防止重复启动程序

   Hook线程也称为钩子线程,当JVM退出的时候会执行Hook线程。经常在程序启动时创建一个

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值