首页
>
Java,
挨踢(IT) > Java7并发示例集102:获取和设置线程信息
Java7并发示例集102:获取和设置线程信息
Thread
类包含几个属性,这些属性所表示的信息能帮助我们识别线程、观察其状态、控制其优先级等。这些线程包括如下几种:
- ID: 该属性表示每个线程的唯一标识;
- Name: 该属性存储每个线程的名称;
- Priority: 该属性存储每个
Thread
对象的优先级。线程优先级分1到10十个级别,1表示最低优先级,10表示最高优先级。并不推荐修改线程的优先级,但是如果确实有这方面的需求,也可以尝试一下。
- Status: 该属性存储线程的状态。线程共有六种不同的状态:新建(new)、运行(runnable)、阻塞(blocked)、等待(waiting)、限时等待(time waiting)或者终止(terminated)。线程的状态必定是其中一种。
在本小节,我们将开发一个程序,程序中新建十个线程,并且设定每个线程的名称和优先级。然后执行线程,观察线程的状态信息,直到线程执行结束。再说明一点,这些线程还是计算一个数的乘法表。
知其然
按照下面所示步骤,来实现该示例:
-
创建一个名为 Calculator
的类,实现Runnable
接口。代码如下:
1 | public class Calculator implements Runnable { |
-
声明一个私有的整形属性,名称为number
,实现该类的构造函数来初始化刚刚声明的属性。代码如下:
3 | public Calculator( int number) { |
-
实现run()
方法,该方法是我们创建的线程执行时运行的程序(instruction),故而该方法用于计算乘法表。具体代码如下:
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); |
-
现在,我们来实现示例应用的主类(main class)。创建名为Main
的类,在该类中添加main
方法。代码如下:
2 | public static void main(String[] args) { |
-
创建两个包含十个元素数组,一个是Thread
类型的,一个是Thread.State
类型,然后全部初始化。这两个数组,一个用于存储我们将以执行的线程,另外一个存储这些线程的状态。代码如下:
1 | Thread[] threads = new Thread[ 10 ]; |
2 | Thread.State[] status = new Thread.State[threads.length]; |
-
创建十个Calculator
对象,并且使用不同的数来初始化每个对象。使用这些Calculator
对象创建十个Thread
对象,存储到上面的创建数组中。同时,设置这些线程的优先级,五个设置成最高优先级;五个设置成最低优先级。代码如下:
1 | for ( int i = 0 ; i < threads.length; i++) { |
2 | threads[i] = new Thread( new Calculator(i)); |
4 | threads[i].setPriority(Thread.MAX_PRIORITY); |
6 | threads[i].setPriority(Thread.MIN_PRIORITY); |
8 | threads[i].setName( "Thread-" + i); |
-
创建一个PrintWriter
对象,用于将线程状态的变换记录到文件中。代码如下:
1 | try (FileWriter file = new FileWriter( "D:\\thread.log" ); |
2 | PrintWriter pw = new PrintWriter(file)) { |
这里使用了Java7的语法,所以请将JDK升级到第七版,把编译工具设置成Java7。否则会报语法错误。
-
将所有线程的状态写到文件中。现在,现在的状态应该是新建(NEW)
。代码如下:
1 | for ( 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(); |
-
启动所有线程。代码入下:
1 | for ( int i = 0 ; i < threads.length; i++) { |
-
另外一方面,我们一直监控线程,直到线程执行结束。如果我们检测到线程的状态有所改变,则立即将线程状态写入到文件中。代码如下:
01 | boolean finish = false ; |
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(); |
11 | for ( int i = 0 ; i < threads.length; i++) { |
13 | && (threads[i].getState() == Thread.State.TERMINATED); |
-
实现writeThreadInfo
方法,该方法将线程的ID、名称、优先级、旧的状态、新的状态写入到文件中。代码如下:
04 | * @param pw PrintWriter对象 |
05 | * @param thread 需要输出状态的线程对象 |
08 | private 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" ); |
-
运行该示例,然后打开thread.log
文件,查看所有线程的演化过程。
知其所以然
下面是thread.log
文件的内容片段。从文件内容可以看出,高优先级的线程大致比低优先级的线程较早完成执行。另外,也可以看到每个线程的状态演化过程。
01 | Main : ******************************** |
02 | Main : Id 11 = Thread- 2 |
04 | Main : Old State: BLOCKED |
05 | Main : New State: TERMINATED |
06 | Main : ******************************** |
07 | Main : Id 13 = Thread- 4 |
09 | Main : Old State: BLOCKED |
10 | Main : New State: TERMINATED |
11 | Main : ******************************** |
12 | Main : Id 14 = Thread- 5 |
14 | Main : Old State: BLOCKED |
15 | Main : New State: TERMINATED |
16 | Main : ******************************** |
下面是控制台的输出片段。输出的是每个线程计算的乘法表,以及所有的线程计算过程。同时,从这里可以更细粒度地看到每个线程的演化过程。
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类的完整代码
01 | package com.diguage.books.concurrencycookbook.chapter1.recipe2; |
08 | public class Calculator implements Runnable { |
11 | public Calculator( int number) { |
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); |
Main类的完整代码
01 | package com.diguage.books.concurrencycookbook.chapter1.recipe2; |
03 | import java.io.FileWriter; |
04 | import java.io.IOException; |
05 | import java.io.PrintWriter; |
13 | public static void main(String[] args) { |
14 | Thread[] threads = new Thread[ 10 ]; |
15 | Thread.State[] status = new Thread.State[threads.length]; |
17 | for ( int i = 0 ; i < threads.length; i++) { |
18 | threads[i] = new Thread( new Calculator(i)); |
20 | threads[i].setPriority(Thread.MAX_PRIORITY); |
22 | threads[i].setPriority(Thread.MIN_PRIORITY); |
24 | threads[i].setName( "Thread-" + i); |
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(); |
36 | for ( int i = 0 ; i < threads.length; i++) { |
40 | boolean finish = false ; |
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(); |
50 | for ( int i = 0 ; i < threads.length; i++) { |
52 | && (threads[i].getState() == Thread.State.TERMINATED); |
56 | } catch (IOException e) { |
64 | * @param pw PrintWriter对象 |
65 | * @param thread 需要输出状态的线程对象 |
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" ); |