Java并发编程示例(二):获取和设置线程信息
thread类包含几个属性,这些属性所表示的信息能帮助我们识别线程、观察其状态、控制其优先级等。这些线程包括如下几种:
id: 该属性表示每个线程的唯一标识;
name: 该属性存储每个线程的名称;
priority: 该属性存储每个thread对象的优先级。线程优先级分1到10十个级别,1表示最低优先级,10表示最高优先级。并不推荐修改线程的优先级,但是如果确实有这方面的需求,也可以尝试一下。
status: 该属性存储线程的状态。线程共有六种不同的状态:新建(new)、运行(runnable)、阻塞(blocked)、等待(waiting)、限时等待(time waiting)或者终止(terminated)。线程的状态必定是其中一种。
在本小节,我们将开发一个程序,程序中新建十个线程,并且设定每个线程的名称和优先级。然后执行线程,观察线程的状态信息,直到线程执行结束。再说明一点,这些线程还是计算一个数的乘法表。
知其然
按照下面所示步骤,来实现该示例:
1.创建一个名为 calculator的类,实现runnable接口。代码如下:
public class calculator implements runnable {
2.声明一个私有的整形属性,名称为number,实现该类的构造函数来初始化刚刚声明的属性。代码如下:
private int number;
public calculator(int number) {
this.number = number;
}
3.实现run()方法,该方法是我们创建的线程执行时运行的程序(instruction),故而该方法用于计算乘法表。具体代码如下:
@override
public void run() {
for (int i = 0; i < 10; i++) {
system.out.printf("%s: %d * %d = %d\n",
thread.currentthread().getname(),
number, i, i * number);
}
}
4.现在,我们来实现示例应用的主类(main class)。创建名为main的类,在该类中添加main方法。代码如下:
public class main {
public static void main(string[] args) {
5.创建两个包含十个元素数组,一个是thread类型的,一个是thread.state类型,然后全部初始化。这两个数组,一个用于存储我们将以执行的线程,另外一个存储这些线程的状态。代码如下:
thread[] threads = new thread[10];
thread.state[] status = new thread.state[threads.length];
6.创建十个calculator对象,并且使用不同的数来初始化每个对象。使用这些calculator对象创建十个thread对象,存储到上面的创建数组中。同时,设置这些线程的优先级,五个设置成最高优先级;五个设置成最低优先级。代码如下:
for (int i = 0; i < threads.length; i++) {
threads[i] = new thread(new calculator(i));
if ((i % 2) == 0) {
threads[i].setpriority(thread.max_priority);
} else {
threads[i].setpriority(thread.min_priority);
}
threads[i].setname("thread-" + i);
}
7.创建一个printwriter对象,用于将线程状态的变换记录到文件中。代码如下:
try (filewriter file = new filewriter("d:\\thread.log");
printwriter pw = new printwriter(file)) {
这里使用了java7的语法,所以请将jdk升级到第七版,把编译工具设置成java7。否则会报语法错误。
8.将所有线程的状态写到文件中。现在,现在的状态应该是新建(new)。代码如下:
for (int i = 0; i < threads.length; i++) {
thread thread = threads[i];
pw.println("main: status of thread " + i +
" : " + threads[i].getstate());
status[i] = threads[i].getstate();
}
9.启动所有线程。代码入下:
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
10.另外一方面,我们一直监控线程,直到线程执行结束。如果我们检测到线程的状态有所改变,则立即将线程状态写入到文件中。代码如下:
boolean finish = false;
while (!finish) {
for (int i = 0; i < threads.length; i++) {
if (threads[i].getstate() != status[i]) {
writethreadinfo(pw, threads[i], status[i]);
status[i] = threads[i].getstate();
}
}
finish = true;
for (int i = 0; i < threads.length; i++) {
finish = finish
&& (threads[i].getstate() == thread.state.terminated);
}
}
11.实现writethreadinfo方法,该方法将线程的id、名称、优先级、旧的状态、新的状态写入到文件中。代码如下:
/**
* 将一个线程的状态输出到一个文件中。
*
* @param pw printwriter对象
* @param thread 需要输出状态的线程对象
* @param state 线程的旧状态
*/
private static void writethreadinfo(printwriter pw,
thread thread, thread.state state) {
pw.printf("main : id %d = %s\n", thread.getid(), thread.getname());
pw.printf("main : priority: %d\n", thread.getpriority());
pw.printf("main : old state: %s\n", state);
pw.printf("main : new state: %s\n", thread.getstate());
pw.printf("main : ********************************\n");
}
12.运行该示例,然后打开thread.log文件,查看所有线程的演化过程。
知其所以然
下面是thread.log文件的内容片段。从文件内容可以看出,高优先级的线程大致比低优先级的线程较早完成执行。另外,也可以看到每个线程的状态演化过程。
main : ********************************
main : id 11 = thread-2
main : priority: 10
main : old state: blocked
main : new state: terminated
main : ********************************
main : id 13 = thread-4
main : priority: 10
main : old state: blocked
main : new state: terminated
main : ********************************
main : id 14 = thread-5
main : priority: 1
main : old state: blocked
main : new state: terminated
main : ********************************
下面是控制台的输出片段。输出的是每个线程计算的乘法表,以及所有的线程计算过程。同时,从这里可以更细粒度地看到每个线程的演化过程。
thread-8: 8 * 2 = 16
thread-8: 8 * 3 = 24
thread-8: 8 * 4 = 32
thread-6: 6 * 0 = 0
thread-6: 6 * 1 = 6
thread-6: 6 * 2 = 12
thread-6: 6 * 3 = 18
thread-6: 6 * 4 = 24
thread-6: 6 * 5 = 30
thread-6: 6 * 6 = 36
thread-6: 6 * 7 = 42
thread-6: 6 * 8 = 48
thread-6: 6 * 9 = 54
thread-5: 5 * 0 = 0
thread-5: 5 * 1 = 5
thread-5: 5 * 2 = 10
thread-5: 5 * 3 = 15
thread-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类的完整代码
package com.diguage.books.concurrencycookbook.chapter1.recipe2;
/**
* date: 2013-09-13
* time: 19:49
*/
public class calculator implements runnable {
private int number;
public calculator(int number) {
this.number = number;
}
@override
public void run() {
for (int i = 0; i < 10; i++) {
system.out.printf("%s: %d * %d = %d\n",
thread.currentthread().getname(),
number, i, i * number);
}
}
}
main类的完整代码
package com.diguage.books.concurrencycookbook.chapter1.recipe2;
import java.io.filewriter;
import java.io.ioexception;
import java.io.printwriter;
/**
* date: 2013-09-13
* time: 19:51
*/
public class main {
public static void main(string[] args) {
thread[] threads = new thread[10];
thread.state[] status = new thread.state[threads.length];
for (int i = 0; i < threads.length; i++) {
threads[i] = new thread(new calculator(i));
if ((i % 2) == 0) {
threads[i].setpriority(thread.max_priority);
} else {
threads[i].setpriority(thread.min_priority);
}
threads[i].setname("thread-" + i);
}
try (filewriter file = new filewriter("d:\\thread.log");
printwriter pw = new printwriter(file)) {
for (int i = 0; i < threads.length; i++) {
thread thread = threads[i];
pw.println("main: status of thread " + i +
" : " + threads[i].getstate());
status[i] = threads[i].getstate();
}
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
boolean finish = false;
while (!finish) {
for (int i = 0; i < threads.length; i++) {
if (threads[i].getstate() != status[i]) {
writethreadinfo(pw, threads[i], status[i]);
status[i] = threads[i].getstate();
}
}
finish = true;
for (int i = 0; i < threads.length; i++) {
finish = finish
&& (threads[i].getstate() == thread.state.terminated);
}
}
} catch (ioexception e) {
e.printstacktrace();
}
}
/**
* 将一个线程的状态输出到一个文件中。
*
* @param pw printwriter对象
* @param thread 需要输出状态的线程对象
* @param state 线程的旧状态
*/
private static void writethreadinfo(printwriter pw,
thread thread, thread.state state) {
pw.printf("main : id %d = %s\n",
thread.getid(), thread.getname());
pw.printf("main : priority: %d\n", thread.getpriority());
pw.printf("main : old state: %s\n", state);
pw.printf("main : new state: %s\n", thread.getstate());
pw.printf("main : ********************************\n");
}
}
上一篇: Java设计模式之创建者模式简介