线程是Java并发API中最基本的元素,每个Java程序都至少有一个执行main()方法的线程,反过来main()方法启动应用的执行。当启动一个新的Thread类时,它将与应用程序的其他线程以及操作系统上的其他进程并行执行。进程和线程之间有一个关键的区别,进程是正在运行的应用实例(例如在文本处理器中编辑文件)。一个或多个线程执行完成此过程的任务,可以运行同一个应用的多个进程,例如文本处理器的两个实例。进程中的线程共享内存,而相同操作系统的进程不共享内存。
能够执行的所有类型的Java任务(Runnable、Callable或fork/join任务)都在线程中执行,所有高级Java并发机制,例如Executor框架和fork/join框架都基于线程池实现。
本节将学习关于Thread类的状态信息,以及如何获取这些信息。
准备工作
本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。
实现过程
通过如下步骤实现范例:
-
创建名为Task的类,实现Runnable接口:
public class Task implements Runnable {
-
实现任务的run()方法:
@Override public void run() {
-
创建重复100次操作的循环:
for (int i=0; i<100; i++) {
-
在每次操作中,设置线程休眠100毫秒:
try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
-
输出线程名称和重复次数到控制台:
System.out.printf("%s: %d\n",Thread.currentThread().getName(),i); } } }
-
创建本范例主类,创建名为Main的类,包含main()方法:
public class Main { public static void main(String[] args) throws Exception{
-
创建名为task的Task对象:
Task task = new Task();
-
创建包含五个元素的Thread数组:
Thread threads[] = new Thread[5];
-
创建并启动五个线程执行之前创建的Task对象:
for (int i = 0; i < 5; i++) { threads[i] = new Thread(task); threads[i].setPriority(i + 1); threads[i].start(); }
-
创建重复10次操作的循环,每次操作输出之前加载的线程信息到控制台,在内部创建重复五次操作的循环:
for (int j = 0; j < 10; j++) { System.out.printf("Main: Logging threads\n"); for (int i = 0; i < threads.length; i++) {
-
输出每个线程的名称、状态、组别和堆栈跟踪的长度到控制台:
System.out.printf("**********************\n"); System.out.printf("Main: %d: Id: %d Name: %s: Priority: %d\n",i, threads[i].getId(),threads[i].getName(), threads[i].getPriority()); System.out.printf("Main: Status: %s\n",threads[i].getState()); System.out.printf("Main: Thread Group: %s\n", threads[i].getThreadGroup()); System.out.printf("Main: Stack Trace: \n");
-
输出线程堆栈跟踪的循环到控制台:
for (int t=0; t<threads[i].getStackTrace().length; t++) { System.out.printf("Main: %s\n",threads[i].getStackTrace()[t]); } System.out.printf("**********************\n"); }
-
设置线程休眠1秒钟,关闭类循环:
TimeUnit.SECONDS.sleep(1); } } }
工作原理
本节使用如下方法的到Thread类的信息:
- getId():返回线程的ID,它是唯一长整型数字,且无法更改。
- getName():返回线程名称,如果没有设置线程名称,Java提供默认名称。
- getPriority():返回线程执行优先级。高优先级的线程优先于低优先级的线程执行,它是int值,在线程类常量MIN_PRIORITY和MAX_PRIORITY之间。默认情况下,创建线程的优先级与Thread类常量NORM_PRIORITY指定的优先级相同。
- getState():返回线程状态,它是Thread.State对象,Thread.State枚举具有线程的所有可能状态。
- getThreadGroup():返回线程的ThreadGroup对象,默认情况下,线程属于相同的线程组,但可以在线程的构造函数中建立一个不同的线程组。
- getStackTrace():返回StackTraceElement对象数组。每个对象都表示对以线程的run()方法开始的方法调用,并包括在实际执行点之前调用的所有方法。当调用新对象时,新的堆栈跟踪元素添加到数组中。当方法结束执行时,其堆栈跟踪元素从数组中移出。
扩展学习
Thread类还有其他方法,提供线程的有用信息。如下所示:
- activeCount():返回线程组中活跃线程数。
- dumpStack():将线程的堆栈跟踪按照标准错误输出。
更多关注
- 第一章“线程管理”中的“创建、运行线程,设置线程属性”小节
- 第八章“定制并发类”中的“执行器对象中使用自定义ThreadFactory”和“实现为fork/join框架生成自定义线程的ThreadFactory接口”小节