您的位置:首页 > 编程语言 > Java开发

[Java并发编程]-线程的六种状态及其状态转换

2015-10-15 15:46 639 查看


1.线程自身信息

线程运行的过程会产生很多信息,这些信息都保存在Thread类中的成员变量里面,常见的有:

a.线程的ID是唯一标识getId()

b.线程的名称:getName(),如果不设置线程名称默认为“Thread-xx”

c.线程的优先级:getPriority,线程优先级从1-10,其中数字越大表示优先级别越高,同时获得JVM调度执行的可能性越大,JDK内置了三种常见的状态:
//最小优先级
public final static int MIN_PRIORITY = 1;

//一般优先级
public final static int NORM_PRIORITY = 5;

//最大优先级
public final static int MAX_PRIORITY = 10;


一般不推荐设置线程的优先级,如果进行设置了非法的优先级程序就会出现IllegalArgumentException异常。


2.线程的几个状态


1.Java线程有六种状态

public enum State {
//线程刚创建
NEW,

//在JVM中正在运行的线程
RUNNABLE,

//线程处于阻塞状态,等待监视锁,可以重新进行同步代码块中执行
BLOCKED,

//等待状态
WAITING,

//调用sleep() join() wait()方法可能导致线程处于等待状态
TIMED_WAITING,

//线程执行完毕,已经退出
TERMINATED;
}


上面六种状态图如下:





2.线程状态的解释

1.当线程继承Thread或者实现了Runnable创建了线程对象后,当new线程对象过后线程就进入了初始的状态。

2.当线程对象调用了start()方法的时候,线程启动进入可运行的状态。

3.线程进入可运行状态后,如果逻辑完成那么线程将会终结,如果没有执行完毕中间JVM分配时间片用完,将进入可运行状态,一旦线程被JVM选中则立即执行。

4.运行状态的情况比较复杂

第一:线程如果执行run() main()方法结束后,完成逻辑,线程就进入Terminated

第二:当线程调用sleep()或者join()方法就会进入Blocked状态,但是要注意的是阻塞的线程是不释放当前所占有的系统资源,当sleep()结束或者join()等待其他线程来到,当前线程则进入Runnable状态等待JVM分配资源。

第三:当线程进入Runnable状态,但是还没有开始运行的时候,此时发现需要的资源处于同步状态synchronized,这个时候线程将会进入Time waiting,JVM会使用队列对这些线程进行控制,既先进行Time waiting的线程会先得到JVM资源进行执行进入Waiting

第四:如果处于Runnable的线程调用yield()让出JVM资源,那么就会进入New状态和其他New状态线程进行竞争重新进入Runnable

第五:如果当前线程调用wait()方法,则当前线程进入Time waiting但是这个时候当前线程会释放所占有的JVM资源,进入这个状态过后是不能自动唤醒的,必须调用notify()或者notifyAll()方法,线程进入Waiting。


3.案例解释

案例:用案例解释线程的六种运行状态,其中Pig类实现Runnable接口,逻辑是打印当前运行的线程信息,
每隔一秒打印一次。在Main方法中启动十个Pig线程设置相应的线程优先级别,并且将初始的线程状态
保存到线程状态数组中,在运行的过程判断当前线程状态和初始状态是否相同,如果不同则打印当前线
程的信息保存到日志文件中。

class Pig implements Runnable {

@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
//线程进行休眠一秒
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前执行线程信息
System.out.println("ThreadName : " + Thread.currentThread().getName());
}
}
}

public class App {
public static void main(String[] args) throws Exception {
// 创建现成数组
Thread[] taskArr = new Thread[10];

// 线程状态数组
Thread.State[] threadStates = new Thread.State[10];

// 设置线程的状态
for (int i = 0; i < 10; i++) {
taskArr[i] = new Thread(new Pig());

// 分别设置状态
if ((i % 3) == 0) {
taskArr[i].setPriority(Thread.NORM_PRIORITY);
} else if ((i % 3) == 1) {
taskArr[i].setPriority(Thread.MIN_PRIORITY);
} else if ((i % 3) == 2) {
taskArr[i].setPriority(Thread.MAX_PRIORITY);
}
}

// 将线程信息写入到文件中便于分析
FileWriter fWriter = new FileWriter(".\\log.txt");
PrintWriter pWriter = new PrintWriter(fWriter);

// 循环遍历获取线程的信息
for (int i = 0; i < 10; i++) {
pWriter.println("线程 " + i + " 状态:" + taskArr[i].getState());

// 将当前线程状态保存到状态数组中
threadStates[i] = taskArr[i].getState();
}

// 启动线程
for (int i = 0; i < 10; i++) {
taskArr[i].start();
}

// 在运行过程中如果线程的状态和初始状态不一样就将状态变化过程写入到文件中
boolean finish = false;

while (!finish) {
for (int i = 0; i < 10; i++) {
// 线程状态发生变化
if (taskArr[i].getState() != threadStates[i]) {
// 打印线程当前信息
printThreadMsg(pWriter, taskArr[i], threadStates[i]);

// 将当前线程状态保存到线程状态数组中
threadStates[i] = taskArr[i].getState();
}
}
finish = true;
for (int i = 0; i < 10; i++) {
finish = finish && (taskArr[i].getState() == State.TERMINATED);
}
}
}

/** * 打印当前线程的信息 * @param pWriter * @param thread * @param state */
private static void printThreadMsg(PrintWriter pWriter, Thread thread, State state) {
pWriter.println("*********************************************************");
pWriter.println("线程ID: " + thread.getId() + " 线程名称:" + thread.getName());
pWriter.println("线程优先级:" + thread.getPriority());
pWriter.println("线程过去状态:" + state);
pWriter.println("线程当前状态:" + thread.getState());
pWriter.println("*********************************************************");
}
}


部分执行结果如下:





分析上面的部分执行结果就可以看出当Pig线程进行休眠的时候,就会导致其他线程状态的变换,其中过去状态和当前状态可以明显的反应出线程状态切换。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐