《Java程序员面试秘笈》—— 1.11 线程的分组

简介: Java并发API提供了一个有趣的功能,它能够把线程分组。这允许我们把一个组的线程当成一个单一的单元,对组内线程对象进行访问并操作它们。例如,对于一些执行同样任务的线程,你想控制它们,不管多少线程在运行,只需要一个单一的调用,所有这些线程的运行都会被中断。

本节书摘来异步社区《Java 7并发编程实战手册》一书中的第1章,第1.11节,作者:【西】Javier Fernández González,更多章节内容可以访问云栖社区“异步社区”公众号查看。

1.11 线程的分组

Java并发API提供了一个有趣的功能,它能够把线程分组。这允许我们把一个组的线程当成一个单一的单元,对组内线程对象进行访问并操作它们。例如,对于一些执行同样任务的线程,你想控制它们,不管多少线程在运行,只需要一个单一的调用,所有这些线程的运行都会被中断。

Java提供ThreadGroup类表示一组线程。线程组可以包含线程对象,也可以包含其他的线程组对象,它是一个树形结构。

在本节中,我们学习并使用ThreadGroup对象类开发一个简单的范例:创建10个线程并让它们休眠一个随机时间(例如模拟一个查询),当其中一个线程查找成功的时候,我们将中断其他的9个线程。

准备工作
本节的范例是在Eclipse IDE里完成的。无论你使用Eclipse还是其他的IDE(比如NetBeans),都可以打开这个IDE并且创建一个新的Java工程。

范例实现
按照接下来的步骤实现本节的范例。

1. 创建一个名为Result的类。它存储先执行完的线程。声明一个私有字符串变量name,并生成读写这个值的方法。

2.创建一个名为SearchTask的类,它实现了Runnable接口。
``
public class SearchTask implements Runnable {``
3.声明一个Result类的私有属性,并实现带参数的构造器(Constructor),来为这个属性设置值。

private Result result;
public SearchTask(Result result) {
  this.result=result;
}```
4.实现run()方法。它将调用doTask()方法,并等待它完成或者抛出一个InterruptedException异常。run()方法也将打印出线程的开始、结束或者中断等信息。

@Override
public void run() {
String name=Thread.currentThread().getName();
System.out.printf("Thread %s: Startn",name);
try {

doTask();
result.setName(name);

} catch (InterruptedException e) {

System.out.printf("Thread %s: Interrupted\n",name);
return;

}
System.out.printf("Thread %s: Endn",name);
}`
5.实现doTask()方法。它创建Random对象来生成一个随机数,并用它做为传入参数调用sleep()方法。

private void doTask() throws InterruptedException {
  Random random=new Random((new Date()).getTime());
  int value=(int)(random.nextDouble()*100);
  System.out.printf("Thread %s: %d\n",Thread.currentThread(). getName(),value);
  TimeUnit.SECONDS.sleep(value);
}```
6.创建一个包含main()方法的主类Main。

public class Main {
public static void main(String[] args) {`
7.创建一个标识为Searcher的线程组对象。
``
ThreadGroup threadGroup = new ThreadGroup("Searcher");``
8.创建一个Result 对象,并用它作为传入参数创建一个SearchTask对象。

Result result=new Result();
SearchTask searchTask=new SearchTask(result);```
9.使用创建的SearchTask对象作为传入参数创建10个线程对象。当调用线程的构造器时,第一个参数是ThreadGroup对象,第二个参数是SearchTask对象。

for (int i=0; i<5; i++) {
Thread thread=new Thread(threadGroup, searchTask);
thread.start();
try {

TimeUnit.SECONDS.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();
}

}`
10.通过list()方法打印线程组对象的信息。

System.out.printf("Number of Threads: %d\n",threadGroup. activeCount());
System.out.printf("Information about the Thread Group\n");
threadGroup.list();```
11.通过activeCount()方法获取线程组包含的线程数目,通过 enumerate()方法获取线程组包含的线程列表。这两个方法可以帮助我们获取每个线程的信息,如线程的状态。

Thread[] threads=new Thread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
for (int i=0; i System.out.printf("Thread %s: %sn",threads[i]. getName(),threads[i].getState());
}`
12.调用waitFinish()方法,我们将在下面实现这个方法。它将等到线程组的第一个线程运行结束。
``
waitFinish(threadGroup);``
13.使用interrupt()方法中断这个组中的其余线程。
``
threadGroup.interrupt();``
14.实现waitFinish()方法。activeCount()方法被用来检测是否有线程运行结束。

 private static void waitFinish(ThreadGroup threadGroup) {
   while (threadGroup.activeCount()>9) {
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}```
15.运行范例并查看运行结果。

工作原理
在下面的截屏中,你会看到list()方法的输出及每个线程对象的状态。

线程组类存储了线程对象和关联的线程组对象,并可以访问它们的信息(例如状态),将执行的操作应用到所有成员上(例如中断)。
<div style="text-align: center"><img src="https://yqfile.alicdn.com/89537ccf2d454f75d20678bba2c0e9ac2ef3ac5d.png" width="" height="">
</div>

更多信息
相关文章
|
1天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
13 0
|
1天前
|
Java
Java中的并发编程:理解和应用线程池
【4月更文挑战第23天】在现代的Java应用程序中,性能和资源的有效利用已经成为了一个重要的考量因素。并发编程是提高应用程序性能的关键手段之一,而线程池则是实现高效并发的重要工具。本文将深入探讨Java中的线程池,包括其基本原理、优势、以及如何在实际开发中有效地使用线程池。我们将通过实例和代码片段,帮助读者理解线程池的概念,并学习如何在Java应用中合理地使用线程池。
|
5天前
|
XML 缓存 Java
Java大厂面试题
Java大厂面试题
18 0
|
5天前
|
存储 安全 Java
Java大厂面试题
Java大厂面试题
11 0
|
5天前
|
存储 安全 Java
Java大厂面试题
Java大厂面试题
13 0
|
6天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
6天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
6天前
|
安全 Java
就只说 3 个 Java 面试题 —— 02
就只说 3 个 Java 面试题 —— 02
19 0
|
6天前
|
存储 安全 Java
就只说 3 个 Java 面试题
就只说 3 个 Java 面试题
10 0
|
6天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。