文档章节

Java并发编程初级篇(九):线程组

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/23 17:33
字数 1110
阅读 89
收藏 0

Java API提供了一个线程组类ThreadGroup,这个类提供了一些方法可以让我们方便地对加入这个线程组的多个线程进行操作。

想使用线程组首先需要实例化一个线程组对象,并把创建的线程加入到这个线程组中。

ThreadGroup group = new ThreadGroup("Searcher");
Thread thread = new Thread(group, Runnable r);

查看Thread的源代码,我们发现在初始化Thread线程对象后,只是把ThreadGroup对象赋值给Thread类的group属性,只有当调用start()方法启动线程的时候,才真正的把线程加入到了线程组中。

/* The group of this thread */
private ThreadGroup group;

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
  ...
  this.group = g;
  ...
)

public synchronized void start() {
  ...
  group.add(this);
  ...
)

下面我们通过一个例子来看一看ThreadGroup为我们提供了那些有用的方法。

先定义一个Runnable类,在这个类中我们让线程休眠一个随机时间,如果在这个休眠时间内线程被中断那么打印中断信息,然后结束线程。如果线程成功执行完毕那么打印线程结束信息。

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        Random random = new Random(new Date().getTime());
        int value = (int)(random.nextDouble() * 100);
        System.out.printf("%s: Started and sleep %ds.\n", Thread.currentThread().getName(), value);
        try {
            TimeUnit.SECONDS.sleep(value);
        } catch (InterruptedException e) {
            System.out.printf("%s: Interrupted.\n", Thread.currentThread().getName());
            return;
        }
        System.out.printf("%s: End.\n", Thread.currentThread().getName());
    }
}

定义主方法类,我们创建10个线程并加入到线程组中。

public class Main {
    public static void main(String[] args) {
        ThreadGroup group = new ThreadGroup("ThreadGroup");

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(group, new MyRunnable());
            thread.start();

            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //获取线程组中线程数量,并打印每一个线程信息。
        System.out.printf("%s: Number of threads is %s.\n", Thread.currentThread().getName(), group.activeCount());
        group.list();

        //使用一个线程数组接收线程组中的所有线程
        Thread[] threads = new Thread[group.activeCount()];
        group.enumerate(threads);
        for (int i = 0; i < threads.length; i++) {
            System.out.printf("%s - %s\n", threads[i].getName(), threads[i].getState());
        }

        //等待第一个线程结束,然后中断剩余所有线程
        while (group.activeCount() > 9) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        group.interrupt();
    }
}

查看控制台日志来对ThreadGroup类的相关方法做一个解释。

首先创建并启动线程,线程内部打印启动信息:

Thread-0: Started and sleep 37s.
Thread-1: Started and sleep 33s.
Thread-2: Started and sleep 28s.
Thread-3: Started and sleep 13s.
Thread-4: Started and sleep 9s.
Thread-5: Started and sleep 12s.
Thread-6: Started and sleep 7s.
Thread-7: Started and sleep 2s.
Thread-8: Started and sleep 34s.
Thread-9: Started and sleep 30s.

接下来调用了ThreadGroup.activeCount()获取了线程组内的线程数量,并调用ThreadGroup.list()打印线程组内线程信息。

main: Number of threads is 10.
java.lang.ThreadGroup[name=ThreadGroup,maxpri=10]
    Thread[Thread-0,5,ThreadGroup]
    Thread[Thread-1,5,ThreadGroup]
    Thread[Thread-2,5,ThreadGroup]
    Thread[Thread-3,5,ThreadGroup]
    Thread[Thread-4,5,ThreadGroup]
    Thread[Thread-5,5,ThreadGroup]
    Thread[Thread-6,5,ThreadGroup]
    Thread[Thread-7,5,ThreadGroup]
    Thread[Thread-8,5,ThreadGroup]
    Thread[Thread-9,5,ThreadGroup]

下面调用ThreadGroup.enumerate(threads)方法用一个线程数组来接收线程组内的线程,并打印线程状态

Thread-0 - TIMED_WAITING
Thread-1 - TIMED_WAITING
Thread-2 - TIMED_WAITING
Thread-3 - TIMED_WAITING
Thread-4 - TIMED_WAITING
Thread-5 - TIMED_WAITING
Thread-6 - TIMED_WAITING
Thread-7 - TIMED_WAITING
Thread-8 - TIMED_WAITING
Thread-9 - TIMED_WAITING

最后我们等待第一个完成的线程后,利用ThreadGroup.interrupt()中断剩余所有线程。

Thread-7: End.
Thread-0: Interrupted.
Thread-2: Interrupted.
Thread-1: Interrupted.
Thread-9: Interrupted.
Thread-8: Interrupted.
Thread-4: Interrupted.
Thread-5: Interrupted.
Thread-6: Interrupted.
Thread-3: Interrupted.

另外通过查看ThreadGroup类的源代码你会发现他实现了异常处理接口Thread.UncaughtExceptionHandler,并重写了方法uncaughtException(),当然你也可以定义自己的类MyThreadGroup extends ThreadGroup,并重写uncaughtException()来实现自己的线程运行时异常处理逻辑。ThreadGroup类中使用的是Thread.getDefaultUncaughtExceptionHandler()来处理异常,要想让这个逻辑起作用,你需要使用Thread.setDefaultUncaughtExceptionHandler()静态方法来为Thread设置静态默认异常处理器,如果没有定义,同样线程会在控制台打印异常堆栈信息。

线程组中线程出现运行时异常会首先调用自己的异常处理器,如果没有定义则会调用线程组的异常处理器,如果还没有定义就会调用默认的异常处理器,并且当线程组中的一个线程抛出异常之后,其余线程都会设置中断状态。

public class ThreadGroup implements Thread.UncaughtExceptionHandler {
	public void uncaughtException(Thread t, Throwable e) {
	    if (parent != null) {
	        parent.uncaughtException(t, e);
	    } else {
	        Thread.UncaughtExceptionHandler ueh =
	            Thread.getDefaultUncaughtExceptionHandler();
	        if (ueh != null) {
	            ueh.uncaughtException(t, e);
	        } else if (!(e instanceof ThreadDeath)) {
	            System.err.print("Exception in thread \""
	                             + t.getName() + "\" ");
	            e.printStackTrace(System.err);
	        }
	    }
	}
}

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 25
博文 91
码字总数 83019
作品 0
西城
程序员
私信 提问
Java面试:投行的15个多线程和并发面试题

本文由ImportNew -一杯哈希不加盐 翻译自dzone。欢迎加入翻译小组。转载请见文末要求。 多线程和并发问题已成为各种 Java 面试中必不可少的一部分。如果你准备参加投行的 Java 开发岗位面试,...

ImportNew
08/23
0
0
Java Concurrent--java.util.Concurrent包

java.util.concurrent并发编程包是专门为Java并发编程设计的,其中设计的类主要分为以下几部分: 显式锁 原子变量 线程池 并发容器 同步工具类 1、显式锁 显式锁相关内容可以看这篇博客:htt...

akane_oimo
05/27
0
0
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0
安卓中高级开发工程师面试之——面试永远逃不掉的Java线程面试题

不管你是Java工程师还是安卓开发工程师,只要你是计算机开发工程师,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大...

小饼干的梦
10/12
0
0
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
8

没有更多内容

加载失败,请刷新页面

加载更多

MariaDB 服务器在 MySQL Workbench 备份数据的时候出错如何解决

服务器是运行在 MariaDB 10.2 上面的,在使用 MySQL Workbench 出现错误: mysqldump: Couldn't execute 'SELECT COLUMN_NAME, JSON_EXTRACT(HISTOGRAM, '$."number-of-buckets-specified"'......

honeymose
今天
2
0
apache顶级项目(二) - B~C

apache顶级项目(二) - B~C https://www.apache.org/ Bahir Apache Bahir provides extensions to multiple distributed analytic platforms, extending their reach with a diversity of s......

晨猫
今天
6
0
day152-2018-11-19-英语流利阅读

“超级食物”竟然是营销噱头? Daniel 2018-11-19 1.今日导读 近几年来,超级食物 superfoods 开始逐渐走红。不难发现,越来越多的轻食餐厅也在不断推出以超级食物为主打食材的健康料理,像是...

飞鱼说编程
今天
12
0
SpringBoot源码:启动过程分析(二)

接着上篇继续分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 一样的,我们先把时序图贴上来,方便理解: 二.源码分析 回顾一下,前面我们分析到了下...

Jacktanger
昨天
4
0
Apache防盗链配置,Directory访问控制,FilesMatch进行访问控制

防盗链配置 通过限制referer来实现防盗链的功能 配置前,使用curl -e 指定referer [root@test-a test-webroot]# curl -e "http://www.test.com/1.html" -x127.0.0.1:80 "www.test.com/1.jpg......

野雪球
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部