首页 > Java, 挨踢(IT) > Java7并发示例集102:获取和设置线程信息

Java7并发示例集102:获取和设置线程信息

2013年9月18日 发表评论 阅读评论 326 人阅读    

Thread类包含几个属性,这些属性所表示的信息能帮助我们识别线程、观察其状态、控制其优先级等。这些线程包括如下几种:

  • ID: 该属性表示每个线程的唯一标识;
  • Name: 该属性存储每个线程的名称;
  • Priority: 该属性存储每个Thread对象的优先级。线程优先级分1到10十个级别,1表示最低优先级,10表示最高优先级。并不推荐修改线程的优先级,但是如果确实有这方面的需求,也可以尝试一下。
  • Status: 该属性存储线程的状态。线程共有六种不同的状态:新建(new)、运行(runnable)、阻塞(blocked)、等待(waiting)、限时等待(time waiting)或者终止(terminated)。线程的状态必定是其中一种。

在本小节,我们将开发一个程序,程序中新建十个线程,并且设定每个线程的名称和优先级。然后执行线程,观察线程的状态信息,直到线程执行结束。再说明一点,这些线程还是计算一个数的乘法表。

知其然

按照下面所示步骤,来实现该示例:

  1. 创建一个名为 Calculator的类,实现Runnable接口。代码如下:

    1public class Calculator implements Runnable {
  2. 声明一个私有的整形属性,名称为number,实现该类的构造函数来初始化刚刚声明的属性。代码如下:

    1private int number;
    2 
    3public Calculator(int number) {
    4    this.number = number;
    5}
  3. 实现run()方法,该方法是我们创建的线程执行时运行的程序(instruction),故而该方法用于计算乘法表。具体代码如下:

    1@Override
    2public void run() {
    3    for (int i = 0; i < 10; i++) {
    4        System.out.printf("%s: %d * %d = %d\n",
    5                Thread.currentThread().getName(),
    6                number, i, i * number);
    7    }
    8}
  4. 现在,我们来实现示例应用的主类(main class)。创建名为Main的类,在该类中添加main方法。代码如下:

    1public class Main {
    2    public static void main(String[] args) {
  5. 创建两个包含十个元素数组,一个是Thread类型的,一个是Thread.State类型,然后全部初始化。这两个数组,一个用于存储我们将以执行的线程,另外一个存储这些线程的状态。代码如下:

    1Thread[] threads = new Thread[10];
    2Thread.State[] status = new Thread.State[threads.length];
  6. 创建十个Calculator对象,并且使用不同的数来初始化每个对象。使用这些Calculator对象创建十个Thread对象,存储到上面的创建数组中。同时,设置这些线程的优先级,五个设置成最高优先级;五个设置成最低优先级。代码如下:

    1for (int i = 0; i < threads.length; i++) {
    2    threads[i] = new Thread(new Calculator(i));
    3    if ((i % 2) == 0) {
    4        threads[i].setPriority(Thread.MAX_PRIORITY);
    5    } else {
    6        threads[i].setPriority(Thread.MIN_PRIORITY);
    7    }
    8    threads[i].setName("Thread-" + i);
    9}
  7. 创建一个PrintWriter对象,用于将线程状态的变换记录到文件中。代码如下:

    1try (FileWriter file = new FileWriter("D:\\thread.log");
    2     PrintWriter pw = new PrintWriter(file)) {

    这里使用了Java7的语法,所以请将JDK升级到第七版,把编译工具设置成Java7。否则会报语法错误。

  8. 将所有线程的状态写到文件中。现在,现在的状态应该是新建(NEW)。代码如下:

    1for (int i = 0; i < threads.length; i++) {
    2    Thread thread = threads[i];
    3    pw.println("Main: Status of Thread " + i +
    4            " : " + threads[i].getState());
    5    status[i] = threads[i].getState();
    6}
  9. 启动所有线程。代码入下:

    1for (int i = 0; i < threads.length; i++) {
    2    threads[i].start();
    3}
  10. 另外一方面,我们一直监控线程,直到线程执行结束。如果我们检测到线程的状态有所改变,则立即将线程状态写入到文件中。代码如下:

    01boolean finish = false;
    02 
    03while (!finish) {
    04    for (int i = 0; i < threads.length; i++) {
    05        if (threads[i].getState() != status[i]) {
    06            writeThreadInfo(pw, threads[i], status[i]);
    07            status[i] = threads[i].getState();
    08        }
    09    }
    10    finish = true;
    11    for (int i = 0; i < threads.length; i++) {
    12        finish = finish
    13                && (threads[i].getState() == Thread.State.TERMINATED);
    14    }
    15}
  11. 实现writeThreadInfo方法,该方法将线程的ID、名称、优先级、旧的状态、新的状态写入到文件中。代码如下:

    01/**
    02 * 将一个线程的状态输出到一个文件中。
    03 *
    04 * @param pw     PrintWriter对象
    05 * @param thread 需要输出状态的线程对象
    06 * @param state  线程的旧状态
    07 */
    08private static void writeThreadInfo(PrintWriter pw,
    09                                  Thread thread, Thread.State state) {
    10    pw.printf("Main : Id %d = %s\n", thread.getId(), thread.getName());
    11    pw.printf("Main : Priority: %d\n", thread.getPriority());
    12    pw.printf("Main : Old State: %s\n", state);
    13    pw.printf("Main : New State: %s\n", thread.getState());
    14    pw.printf("Main : ********************************\n");
    15}
  12. 运行该示例,然后打开thread.log文件,查看所有线程的演化过程。

知其所以然

下面是thread.log文件的内容片段。从文件内容可以看出,高优先级的线程大致比低优先级的线程较早完成执行。另外,也可以看到每个线程的状态演化过程。

01Main : ********************************
02Main : Id 11 = Thread-2
03Main : Priority: 10
04Main : Old State: BLOCKED
05Main : New State: TERMINATED
06Main : ********************************
07Main : Id 13 = Thread-4
08Main : Priority: 10
09Main : Old State: BLOCKED
10Main : New State: TERMINATED
11Main : ********************************
12Main : Id 14 = Thread-5
13Main : Priority: 1
14Main : Old State: BLOCKED
15Main : New State: TERMINATED
16Main : ********************************

下面是控制台的输出片段。输出的是每个线程计算的乘法表,以及所有的线程计算过程。同时,从这里可以更细粒度地看到每个线程的演化过程。

01Thread-8: 8 * 2 = 16
02Thread-8: 8 * 3 = 24
03Thread-8: 8 * 4 = 32
04Thread-6: 6 * 0 = 0
05Thread-6: 6 * 1 = 6
06Thread-6: 6 * 2 = 12
07Thread-6: 6 * 3 = 18
08Thread-6: 6 * 4 = 24
09Thread-6: 6 * 5 = 30
10Thread-6: 6 * 6 = 36
11Thread-6: 6 * 7 = 42
12Thread-6: 6 * 8 = 48
13Thread-6: 6 * 9 = 54
14Thread-5: 5 * 0 = 0
15Thread-5: 5 * 1 = 5
16Thread-5: 5 * 2 = 10
17Thread-5: 5 * 3 = 15
18Thread-5: 5 * 4 = 20

Thread类有可以存储线程信息所需的所有属性。Java虚拟机使用线程优先级来每个时刻调度一个线程来使用CPU,并且根据线程的情况来设置其每个线程的状态。

如果没有设置线程的名称,Java虚拟机会使用这种格式来时分配一个名称,Thread-XX,其中XX是一个数字。我们不能修改线程的ID以及线程的状态。Thread类也没有实现setId()setStatus()方法,以允许做出这些修改。

永无止境

在本节,我们学习了如何使用Thread对象来访问线程信息。其实,Runnable的实现类也运行我们访问这些信息。Thread类的静态方法currentThread()可以获取正在执行的Runnable实现类的对象,进而访问线程的信息。

需要注意的是,如果尝试设置1到10以外的优先级,setPriority()会抛出名为IllegalArgumentException的异常,

拿来主义

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

小有所成

Calculator类的完整代码

01package com.diguage.books.concurrencycookbook.chapter1.recipe2;
02 
03/**
04 * Coder: D瓜哥,http://www.diguage.com/
05 * Date: 2013-09-13
06 * Time: 19:49
07 */
08public class Calculator implements Runnable {
09    private int number;
10 
11    public Calculator(int number) {
12        this.number = number;
13    }
14 
15    @Override
16    public void run() {
17        for (int i = 0; i < 10; i++) {
18            System.out.printf("%s: %d * %d = %d\n",
19                    Thread.currentThread().getName(),
20                    number, i, i * number);
21        }
22    }
23}

Main类的完整代码

01package com.diguage.books.concurrencycookbook.chapter1.recipe2;
02 
03import java.io.FileWriter;
04import java.io.IOException;
05import java.io.PrintWriter;
06 
07/**
08 * Coder: D瓜哥,http://www.diguage.com/
09 * Date: 2013-09-13
10 * Time: 19:51
11 */
12public class Main {
13    public static void main(String[] args) {
14        Thread[] threads = new Thread[10];
15        Thread.State[] status = new Thread.State[threads.length];
16 
17        for (int i = 0; i < threads.length; i++) {
18            threads[i] = new Thread(new Calculator(i));
19            if ((i % 2) == 0) {
20                threads[i].setPriority(Thread.MAX_PRIORITY);
21            } else {
22                threads[i].setPriority(Thread.MIN_PRIORITY);
23            }
24            threads[i].setName("Thread-" + i);
25        }
26 
27        try (FileWriter file = new FileWriter("D:\\thread.log");
28             PrintWriter pw = new PrintWriter(file)) {
29            for (int i = 0; i < threads.length; i++) {
30                Thread thread = threads[i];
31                pw.println("Main: Status of Thread " + i +
32                        " : " + threads[i].getState());
33                status[i] = threads[i].getState();
34            }
35 
36            for (int i = 0; i < threads.length; i++) {
37                threads[i].start();
38            }
39 
40            boolean finish = false;
41 
42            while (!finish) {
43                for (int i = 0; i < threads.length; i++) {
44                    if (threads[i].getState() != status[i]) {
45                        writeThreadInfo(pw, threads[i], status[i]);
46                        status[i] = threads[i].getState();
47                    }
48                }
49                finish = true;
50                for (int i = 0; i < threads.length; i++) {
51                    finish = finish
52                            && (threads[i].getState() == Thread.State.TERMINATED);
53                }
54            }
55 
56        } catch (IOException e) {
57            e.printStackTrace();
58        }
59    }
60 
61    /**
62     * 将一个线程的状态输出到一个文件中。
63     *
64     * @param pw     PrintWriter对象
65     * @param thread 需要输出状态的线程对象
66     * @param state  线程的旧状态
67     */
68    private static void writeThreadInfo(PrintWriter pw,
69                                      Thread thread, Thread.State state) {
70        pw.printf("Main : Id %d = %s\n",
71                    thread.getId(), thread.getName());
72        pw.printf("Main : Priority: %d\n", thread.getPriority());
73        pw.printf("Main : Old State: %s\n", state);
74        pw.printf("Main : New State: %s\n", thread.getState());
75        pw.printf("Main : ********************************\n");
76    }
77}

 



作 者: D瓜哥,https://www.diguage.com/
原文链接:https://wordpress.diguage.com/archives/44.html
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。

分类: Java, 挨踢(IT) 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.