1.3 线程信息的获取和设置
Thread类有一些保存信息的属性,这些属性可以用来标识线程,显示线程的状态或者控制线程的优先级。
ID:保存了线程的唯一标示符。
Name:保存了线程名称
Priority:保存了线程对象的优先级。线程的优先级是从1到10,其中1是最低优先级;10是最高优先级。我们并不推荐去改变线程的优先级,然而,在需要的时候,也可以这么做。
Status:保存了线程的状态。在Java中,线程的状态有6种:new、runnable、blocked、waiting、time waiting或者 terminated。
在本节,我们将编写程序为10个线程指定名称和优先级,并且输出它们的状态信息直到线程结束。每个线程都将计算一个数字的乘法表。
准备工作
本节的范例是在Eclipse IDE里完成的。无论你使用Eclipse还是其他的IDE(比如NetBeans),都可以打开这个IDE并且创建一个新的Java工程。
范例实现
按照接下来的步骤实现本节的范例。
1.创建一个名为Calculator的类,它实现了Runnable接口。
``
public class Calculator implements Runnable {``
2.声明一个名为number的私有int属性。编写这个类的一个构造器,用来为属性number设置值。
private int number;
public Calculator(int number) {
this.number=number;
}```
3.编写run()方法。这个方法用来执行我们创建的线程的指令,本范例中它将对指定的数字进行乘法表运算。
@Override
public void run() {
for (int i=1; i<=10; i++){
System.out.printf("%s: %d * %d = %d\n",Thread. currentThread().getName(),number,i,i*number);
}
}`
4.编写范例的主类。创建一个名为Main的类,创建的时候同时生成main()方法。
public class Main {
public static void main(String[] args) {```
5. 创建一个容量为10的线程数组,以用来存储线程;创建一个容量为10的Thread.State数组,以用来存放这10个线程运行时的状态。
Thread threads[]=new Thread[10];
Thread.State status[]=new Thread.State[10];`
6.创建一个容量为10的Calculator对象数组,为每个对象都设置不同的数字,然后使用它们作为Thread构造器的参数来创建10个线程对象。并且将其中5个线程的优先级设置为最高,另外5个线程的优先级设置为最低。
for (int i=0; i<10; i++){
threads[i]=new Thread(new Calculator(i));
if ((i%2)==0){
threads[i].setPriority(Thread.MAX_PRIORITY);
} else {
threads[i].setPriorit87y(Thread.MIN_PRIORITY);
}
threads[i].setName("Thread "+i);
}```
7.创建一个PrintWriter对象,用来把线程的状态演变写入到文件中。
try (FileWriter file = new FileWriter(".\data\log.txt");PrintWriter pw = new PrintWriter(file);){`
8.把这10个线程的状态写入文件中。现在线程的状态是NEW。
for (int i=0; i<10; i++){
pw.println("Main : Status of Thread "+i+" : " +threads[i].getState());
status[i]=threads[i].getState();
}```
9.开始执行10个线程。
for (int i=0; i<10; i++){
threads[i].start();
}`
10.直到10个线程都运行完成,我们就可以查看他们的状态。所有任何一个线程的状态发生了变化,我们就会将它写入到文件中。
boolean finish=false;
while (!finish) {
for (int i=0; i<10; 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<10; i++){
finish=finish &&(threads[i].getState()==State.TERMINATED);
}
}```
11.编写writeThreadInfo()方法,用来写下线程的ID、名称、优先级、旧的状态和新的状态。
private static void writeThreadInfo(PrintWriter pw, Thread
thread, State state) {
pw.printf("Main : Id %d - %sn",thread.getId(),thread.getName());
pw.printf("Main : Priority: %dn",thread.getPriority());
pw.printf("Main : Old State: %sn",state);
pw.printf("Main : New State: %sn",thread.getState());
pw.printf("Main : n");
}`
12.运行这个范例,然后打开log.txt文件来查看10个线程的状态演变。
工作原理
下面的截屏是log.txt文件的一部分。在这个文件里,我们可以看到最高优先级的线程比最低优先级的线程结束得早。我们也可以看到每个线程的状态演变。
这个程序的乘法表运算显示在控制台上,每个线程的状态演变记录在log.txt里。这样你可以更清楚地看到线程的演变过程。
Thread类的属性存储了线程的所有信息。JVM使用线程的priority属性来决定某一刻由哪个线程来使用CPU,并且根据线程的情景为它们设置实际状态。
如果没有为线程指定一个名字,JVM将自动给它分配一个名字,格式是Thread-XX,其中XX是一组数字。线程的ID和状态是不允许被修改的,线程类没有提供setId()和setStatus()方法来修改它们。
更多信息
通过本节,你已经学会了如何通过Thread对象访问属性信息。但是,也可以通过实现Runnable接口的对象来访问这些属性信息。如果一个线程是以Runnable对象为参数构建的,那么也可以使用Thread类的静态方法currentThread()来访问这个线程对象。
要注意的是,如果使用setPriority()方法设置的优先级不是从1到10这个范围内的值,运行时就会抛出IllegalArgumentException异常。