欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java并发编程示例(十):线程组

程序员文章站 2024-03-31 16:13:52
对线程分组是java并发api提供的一个有趣功能。我们可以将一组线程看成一个独立单元,并且可以随意操纵线程组中的线程对象。比如,可以控制一组线程来运行同样的任务,无需关心有...

对线程分组是java并发api提供的一个有趣功能。我们可以将一组线程看成一个独立单元,并且可以随意操纵线程组中的线程对象。比如,可以控制一组线程来运行同样的任务,无需关心有多少线程还在运行,还可以使用一次中断调用中断所有线程的执行。

java提供了threadgroup类来控制一个线程组。一个线程组可以通过线程对象来创建,也可以由其他线程组来创建,生成一个树形结构的线程。

根据《effective java》的说明,不再建议使用threadgroup。建议使用executor。

——d瓜哥特此说明。

在本节,我们就使用threadgroup来开发一个简单的示例。我们将创建十个休眠时间不等的线程(比如模拟搜索),当其中一个完成时,中断其余线程。

知其然

按照下面所示步骤,完成示例代码。

1.创建一个名为result的类,用于存储第一个完成任务的线程的名字。声明一个string类型的私有变量,name,同时生成setter/getter方法。代码如下:

复制代码 代码如下:

public class result {
    private string name;

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }
}

2.创建一个名为searchtask的类,并实现runnable接口。代码如下:

复制代码 代码如下:

public class searchtask implements runnable {

3.声明一个result类型的私有变量,并通过构造函数来实例化该变量。代码如下:

复制代码 代码如下:

private result result;

public searchtask(result result) {
    this.result = result;
}

4.实现run()方法,在其中调用dotask()方法,来等待完成或被中断。该方法还向控制台打印信息来显示线程的开始、结束或者中断。代码如下:

复制代码 代码如下:

@override
public void run() {
    string name = thread.currentthread().getname();
    system.out.printf("thread %s: start\n", name);
    try {
        dotask();
        result.setname(name);
    } catch (interruptedexception e) {
        system.out.printf("thread %s: interrupted\n", name);
        return;
    }
    system.out.printf("thread %s: end\n", name);
}

5.实现dotask()方法,该方法将创建一个random对象,然后使用该对象生成一个随机数,来调节线程休眠的时间。代码如下:

复制代码 代码如下:

// 模拟搜索
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 threadgroup = new threadgroup("searcher");

8.然后,创建一个result对象和searchtask对象。代码如下:

复制代码 代码如下:

result result = new result();
searchtask searchtask = new searchtask(result);

9.searchtask对象使用创建十个thread对象,并且创建thread对象时,将threadgroup对象作为第一个参数,传递给thread类的构造函数。代码如下:
复制代码 代码如下:

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()方法将threadgroup对象的信息打印出来。代码如下:

复制代码 代码如下:

system.out.printf("number of threads: %d\n", threadgroup.activecount());
system.out.println("information about the thread group");
threadgroup.list();

11.使用activecount()和enumerate()来获取threadgroup对象中的活跃线程数并将其复制到一个线程数组中。使用get*()方法,获取线程的名称和状态。代码如下:

复制代码 代码如下:

thread[] threads = new thread[threadgroup.activecount()];
threadgroup.enumerate(threads);
for (int i = 0; i < threadgroup.activecount(); i++) {
    system.out.printf("thread %s: %s\n", threads[i].getname(),
            threads[i].getstate());
}

12.调用waitfinish()方法,等待threadgroup对象中的其中一个线程完成任务。稍后实现该方法。代码如下:

复制代码 代码如下:

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()方法的输出,各个线程的状态等。

复制代码 代码如下:

thread thread-0: start
thread thread-0: 52
thread thread-1: start
thread thread-1: 41
thread thread-2: start
thread thread-2: 69
thread thread-3: start
thread thread-3: 60
thread thread-4: start
thread thread-4: 88
number of threads: 5
information about the thread group
java.lang.threadgroup[name=searcher,maxpri=10]
    thread[thread-0,5,searcher]
    thread[thread-1,5,searcher]
    thread[thread-2,5,searcher]
    thread[thread-3,5,searcher]
    thread[thread-4,5,searcher]
thread thread-0: timed_waiting
thread thread-1: timed_waiting
thread thread-2: timed_waiting
thread thread-3: timed_waiting
thread thread-4: timed_waiting
thread thread-1: interrupted
thread thread-4: interrupted
thread thread-2: interrupted
thread thread-0: interrupted
thread thread-3: interrupted

threadgroup类保存着众多thread对象以及关联的threadgroup对象。可以通过调用该类的方法,访问线程的信息,还可以对其进行各种操作,比如中断等。

永无止境

threadgroup类还有好多方法。请翻阅api文档,查看完整的方法说明。

拿来主义

本文是从 《java 7 concurrency cookbook》 (d瓜哥窃译为 《java7并发示例集》 )翻译而来,仅作为学习资料使用。没有授权,不得用于任何商业行为。

小有所成

下面是本节示例所用的代码的完整版。

result类的完整代码:

复制代码 代码如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe10;

/**
 * 存储查询结果
 * date: 2013-09-30
 * time: 00:45
 */
public class result {
    private string name;

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }
}


searchtask类的完整代码
复制代码 代码如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe10;

import java.util.date;
import java.util.random;
import java.util.concurrent.timeunit;

/**
 * 模拟搜索类
 * date: 2013-10-02
 * time: 22:38
 */
public class searchtask implements runnable {
    private result result;

    public searchtask(result result) {
        this.result = result;
    }

    @override
    public void run() {
        string name = thread.currentthread().getname();
        system.out.printf("thread %s: start\n", name);
        try {
            dotask();
            result.setname(name);
        } catch (interruptedexception e) {
            system.out.printf("thread %s: interrupted\n", name);
            return;
        }
        system.out.printf("thread %s: end\n", name);
    }

    // 模拟搜索
    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);
    }
}

main类的完整代码:

复制代码 代码如下:

package com.diguage.books.concurrencycookbook.chapter1.recipe10;

import java.util.concurrent.timeunit;

/**
 * 线程组示例主类
 * date: 2013-10-02
 * time: 22:45
 */
public class main {
    public static void main(string[] args) {
        threadgroup threadgroup = new threadgroup("searcher");

        result result = new result();
        searchtask searchtask = new searchtask(result);

        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();
            }
        }

        system.out.printf("number of threads: %d\n", threadgroup.activecount());
        system.out.println("information about the thread group");
        threadgroup.list();

        thread[] threads = new thread[threadgroup.activecount()];
        threadgroup.enumerate(threads);
        for (int i = 0; i < threadgroup.activecount(); i++) {
            system.out.printf("thread %s: %s\n", threads[i].getname(),
                    threads[i].getstate());
        }

        waitfinish(threadgroup);

        threadgroup.interrupt();
    }

    // 等待任务完成
    private static void waitfinish(threadgroup threadgroup) {
        while (threadgroup.activecount() > 9) {
            try {
                timeunit.seconds.sleep(1);
            } catch (interruptedexception e) {
                e.printstacktrace();
            }
        }
    }
}