文档章节

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

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/23 17:33
字数 1110
阅读 56
收藏 0
点赞 0
评论 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);
	        }
	    }
	}
}

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 20
博文 91
码字总数 83019
作品 0
西城
程序员
并发编程包--java.util.Concurrent

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

霍淇滨
05/27
0
0
读书笔记之《Java并发编程的艺术》-并发编程基础

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

Hi徐敏
2015/11/11
0
8
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

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

Hi徐敏
2015/11/11
0
1
读书笔记之《Java并发编程的艺术》-线程池和Executor的子孙们

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

Hi徐敏
2015/11/11
0
1
【转】15个顶级Java多线程面试题及回答

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

一只死笨死笨的猪
2014/09/30
0
0
15个顶级Java多线程面试题及回答

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

LCZ777
2014/05/27
0
0
Java 编程之美:并发编程高级篇之一

本文来自作者 追梦 在 GitChat 上分享 「Java 编程之美:并发编程高级篇之一」 编辑 | 工藤 前言 借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。 ...

gitchat
05/24
0
0
Java 50道Java线程面试题

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚的Java开发职位都要求开发者...

swearyd457
2015/08/11
0
0
【转】Java线程面试题Top50

目录(?)[-] 50道Java线程面试题 1 什么是线程 2 线程和进程有什么区别 3 如何在Java中实现线程 4 用Runnable还是Thread 6 Thread 类中的start 和 run 方法有什么区别 7 Java中Runnable和Cal...

gehui
2015/08/14
0
0
Java线程面试题 Top 50

不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚的Java开发职位都要求开发者...

loda0128
2015/05/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JVM学习手册(一):查看堆内存使用情况以及排错

平时出现内存溢出以及死锁,一般处理方式都是查看日志,找到抛出异常的代码行,然后本地分析代码,但是这样对于线上排查十分糟糕,这段时间在研究JVM发现了几个比较好的工具和指令. 1.针对频繁GC和...

勤奋的蚂蚁
1分钟前
0
0
Java IO类库之ObjectInputStream和ObjectOutPutStream

一、ObjectOutputStream 1 - ObjectOuputStream介绍 ObjectOutputStream(对象字节输出流),用于将一个序列化对象写入到创建ObjectOutputStream时传入的底层字节输入流中,通过源码可知该类继...

老韭菜
14分钟前
0
0
17.TCP:传输控制协议

介绍 TCP和UDP使用同一网络层(IP),但TCP提供了面向连接、可靠的传输层服务 TCP传输给IP层的信息单位称为报文段或段 TCP通过如下方式保证可靠性: 应用数据被分割成TCP认为最合适发送的数据...

loda0128
23分钟前
0
0
重装Oracle时出现environment variable "PATH"错误的解决办法

在win7 64位下重新安装oracle 11g,一直报environment variable "PATH"的错误,按说明将path里多余的路径删除,但没办法解决。选择忽略错误继续安装,装一半会报CRC错误,还是安装失败。最好...

良言
28分钟前
0
0
TensorFlow 全连接的mnist

全连接的mnist import tensorflow as tf# 导入 MINST 数据集from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets("MNIST_data/", one_ho......

阿豪boy
29分钟前
0
0
JAVA 三种WebService 规范

JAVA 中共有三种WebService 规范,分别是JAX-WS(JAX-RPC)、JAXM&SAAJ、JAX-RS。 1. Jaxws(掌握) JAX-WS 的全称为 Java API for XML-Based Webservices ,早期的基于SOAP 的JAVA 的Web 服务...

onedotdot
48分钟前
0
0
将博客搬至CSDN

将博客搬至CSDN

xpbob
49分钟前
1
0
Aidl进程间通信详细介绍

目录介绍 1.问题答疑 2.Aidl相关属性介绍 2.1 AIDL所支持的数据类型 2.2 服务端和客户端 2.3 AIDL的基本概念 3.实际开发中案例操作 3.1 aidl通信业务需求 3.2 操作步骤伪代码 3.3 服务端操作...

潇湘剑雨
今天
0
0
python爬虫日志(3)下载图片

import urlliburl='https://xxx.jpg'#图片地址res=urllib.request.urlopen(url)#此函数用于对url的访问data=res.read() #字节流with open(r'D:\1.jpg',"wb") as code: c...

茫羽行
今天
0
0
vue中$emit的用法

1、父组件可以使用 props 把数据传给子组件。 2、子组件可以使用 $emit 触发父组件的自定义事件。 vm.$emit( event, arg ) //触发当前实例上的事件 vm.$on( event, fn );//监听event事件后运...

JamesView
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部