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

Java多线程与并发学习之(三):线程的各种状态

2017-06-26 20:01 936 查看
  Java中线程的状态转换问题,自己一直没有完全缕清晰,了解个大概,细节上却又模棱两可,究其原因,还是没有仔细的去细致了解相关知识点,今天就花时间整理一下这部分的相关内容。

  关于java中线程状态问题,网络上各种答案都有,比如单就“线程状态”有哪几种这个问题,就可以找到好多种,有3种的、4种的、5种的、6种的和7种的,线程状态间的转换关系图,更是百花齐放,如果你不是很清晰,绝对会迷失在这些状态的迷宫中。

  3种的(就绪、阻塞和运行):



  4种的(运行、就绪、挂起和结束):



  5种的(
4000
新建、可运行、运行、阻塞和死亡):





  还有6种的(初始、运行就绪、运行、阻塞、等待、等待队列及终止【为什么图上7种,后续有解释】):



  7种的(初始、可运行、运行、阻塞、锁池、等待池及终止):



  还有:

 




  如果你跟我一样,一直对线程状态问题有疑惑,我相信你会有一种越看越蒙的感觉。我仔细想了下造成这种局面的原因,网络上很多博文上的解释,都是按照理解的思路去进行讲解的,但java中对线程状态的理解和真实之间有一些差异,理解java中的线程状态时粒度会更细,真实情况下java对线程进行封装时,进行了部分的简化,这两部分之间的信息差异,导致出现了各种不同理解的状态图。不能说哪一种是错的或者不完善的,只是理解的角度以及粒度不同而已。

  Java中的线程状态到底有几种呢?6种,Java中线程的状态值枚举放到了java.lang.Thread.State枚举类中,这是一个Thread类的内部枚举类。

public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,//初始状态

/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,//运行状态

/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,//阻塞状态

/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,//等待状态

/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,//超时等待状态

/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;//终止状态
}
  (1).NEW(初始状态):当用new操作符创建一个新线程时,如new Thread(r), 该线程还没有开始运行,此时线程处于初始状态。

  (2).RUNNABLE(运行状态):线程调用thread.start();方法后,线程处于该状态。实质上,java中该状态对应两个更细粒度的线程状态,Runnable【可运行(也叫就绪状态)】和Running【运行中】,可运行表示线程已经做好了运行的准备,但能否进入运行中状态,需要看CPU是否分配时间片资源给该线程,如果该线程抢到了CPU资源,则进入到运行中状态;如果运行中状态的线程失去了CPU资源,就会变成可运行状态,知道再次获取到CPU资源,或者触发其他条件,使线程状态转换为其他状态。

  (3).BLOCKED(阻塞状态):多个线程并发时才有产生这种线程状态的条件,当线程等待进入临界区时,就处于该种状态。(临界区概念后续其他章节会介绍,暂时理解成一个代码块即可)

  (4).WAITING(等待状态):该状态也是多线程并发时才会出现,当一个线程获取到了某把锁后,拥有了执行临界区代码的权力,然后调用wait()方法,此时线程处于等待状态。需要区分Blocked状态和Waiting状态,前者是等待进入临界区,也就是等待获取锁;或者是获取锁后,挂起该线程进行等待,直到被唤醒。

  (5).TIMED_WAITING(超时等待状态):该状态跟Waiting状态比较类似,是有时间限制的等待状态,线程获取锁后,调用wait(long time)方法时,线程处于该状态。

  (6).TERMINATED(终止状态):线程执行完毕,或者线程异常了,线程都会变成终止状态。

  

  java中各种状态间转换图如下(参考《Java并发编程的艺术》一书):



  线程在什么情况下会处于各种不同的状态呢,下面逐一用例子进行说明,有的状态下的例子,这里列举的只是最基本的产生场景,实际应用中可能稍复杂一些。

  (1).NEW(初始状态)

public class NewStateTest {
public static void main(String[] args) {
Thread t = new Thread ("Thread_NEW");
System. out.println("线程" + t.getName() + "当前的状态为:" +t.getState());
}
}


  这个不做过多解释,很容易理解,new产生一个线程对象时,线程即为初始状态。

 
(2).RUNNABLE(运行状态)

 public class RunnableStateTest {

public static void main(String[] args) throws InterruptedException {
Thread t = new Thread("Thread_RUNNABLE"){
public void run(){
//System. out.println("线程" + this.getName() + "当前的状态为:" +this.getState());
for(int i=0; i<100000000; i++){
//System. out.println(i);
}
}
};
t.start();
System. out.println("线程" + t.getName() + "当前的状态为:" +t.getState());
}
}



  new产生线程对象t后,调用t.start();方法,线程在执行完毕前,处于可执行(Runnable)状态。

  (3).BLOCKED(阻塞状态)

public class BlockedStateTest {
public static void main(String[] args) {
final Object lock = new Object();

Runnable run = new Runnable() {
@Override
public void run() {
synchronized (lock) {
for(int i=0; i<Integer.MAX_VALUE; i++){
//System. out.println(i);
}
}
}
};

Thread t1 = new Thread(run);
t1.setName("ThreadA");
Thread t2 = new Thread(run);
t2.setName("ThreadB");
t1.start();
t2.start();
System. out.println("线程" + t1.getName() + "当前的状态为:" +t1.getState());
System. out.println("线程" + t2.getName() + "当前的状态为:" +t2.getState());
}

}

  线程ThreadA先抢到锁,处于可执行(Runnable)状态,此时ThreadB也需要执行临界区代码,获取不到锁,处于阻塞(Blocked)状态。

  (4).WAITING(等待状态)

public class WaitingStateTest {

public static void main(String[] args) throws InterruptedException {
final Object lock = new Object();
Thread t1 = new Thread(){
@Override
public void run() {
while(true ){
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {

}
}
}
}
};

Thread t2 = new Thread(){
@Override
public void run() {

while(true ){
synchronized (lock) {
for(int i = 0; i< 10000000; i++){
//System. out.println(i);
}
lock.notifyAll();
}

}
}
};

t1.setName("ThreadA");
t2.setName("ThreadB");

t1.start();
Thread.sleep(50);
t2.start();
System. out.println("线程" + t1.getName() + "当前的状态为:" +t1.getState());
System. out.println("线程" + t2.getName() + "当前的状态为:" +t2.getState());
}
}

  此时线程ThreadA处于等待(Waiting)状态,等待被其他线程唤醒;线程ThreadB处于可运行(Runnable)状态,其运行完for循环后,会唤醒线程ThreadA。

 
(5).TIMED_WAITING(超时等待状态)

public class WaitingStateTest2 {

public static void main(String[] args) throws InterruptedException {
final Object lock = new Object();
Thread t1 = new Thread(){
@Override
public void run() {
while(true ){
synchronized (lock) {
try {
lock.wait(5000);
} catch (InterruptedException e) {

}
}
}
}
};

Thread t2 = new Thread(){
@Override
public void run() {

while(true ){
synchronized (lock) {
for(int i = 0; i< 10000000; i++){
//System. out.println(i);
}
lock.notifyAll();
}

}
}
};

bec4

t1.setName("ThreadA");
t2.setName("ThreadB");

t1.start();
Thread.sleep(50);
t2.start();
System. out.println("线程" + t1.getName() + "当前的状态为:" +t1.getState());
System. out.println("线程" + t2.getName() + "当前的状态为:" +t2.getState());
}
}


  等待超时状态跟等待状态类似,代码上只需要在wait(3000)方法中添加超时参数即可,此时ThreadA处于等待超时(TIMED_WAITING)状态。

 
(6).TERMINATED(终止状态)

public class RunnableStateTest {

public static void main(String[] args) throws InterruptedException {
Thread t = new Thread("Thread_RUNNABLE"){
public void run(){
//System. out.println("线程" + this.getName() + "当前的状态为:" +this.getState());
for(int i=0; i<100; i++){
//System. out.println(i);
}
}
};
t.start();
System. out.println("线程" + t.getName() + "当前的状态为:" +t.getState());
Thread.sleep(500);
System.out.println("等待了1s,确保线程执行完毕");
System. out.println("线程" + t.getName() + "当前的状态为:" +t.getState());
}
}


  例子在NEW状态的例子上稍稍改动即可,当线程执行完毕后,处于终止(TERMINATED)状态。
 

  再介绍两个概念:锁池和等待池

  在java中,每个对象都有两个池,锁池和等待池。

  (1).锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,这些线程就进入了该对象的锁池中。可以这么理解,那些欲获取对象锁而暂时未获取到对象锁的线程,都处在一个叫“锁池”的地方。

  (2).等待池:如果线程A调用了某对象的wait()方法,该线程会释放锁,并且进入该对象的等待池中。某个对象的等待池中的线程,只有等另外的对象调用notify()或者notifyAll()方法时,才会被唤醒,进入争夺锁的行列即进入锁池中,如果争得了锁,就可以执行对应代码块,剩余没争夺到锁的继续在锁池中,等待该线程释放锁后再次争夺。

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息