目录
一,了解状态.
状态是针对当前的线程调度的情况来描述的.我们现在认为线程是调度的基本单位.因此状态更应该是线程的属性(谈到状态一般都是考虑线程的状态).
而在Java中,对于线程的状态进行了细化.有以下几种:
1.NEW : 表明创建了Thread对象但是还没有调用start方法(内核中还没有创建对应的PCB,也没有创建相应的线程).
2. TERMINATED : 表示内核中的PCB已经释放了,但是Thread对象还在.
3.RUNNABLE : 可运行的.包括 a)正坐在CPU上执行的.b) 在就绪队列里,可以随时去CPU上运行的.
4.表示阻塞的状态:
WAITING,TIMED_WAITING,BLOCKED.这三种都是表示阻塞,但是形成的原因不同.
二.线程之间的转换
线程的转换就由下面这张图来解释(图比较丑,手残).
三,线程的状态演示
3.1 NEW和TERMINATED
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for(int i = 0;i<1000000;i++){
}
});
//t调用start之前,是NEW状态.
System.out.println("线程执行之前:"+t.getState());
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//线程执行完毕之后,就是TERMINATED状态.
System.out.println("线程执行之后:"+t.getState());
}
}
在这个程序之中,我们首先创建了一个Thread对象,然后运用lambda表达式来实现run方法.在run方法之中什么都不做,只是循环.然后打印在t.start之前和t线程运行完之后,线程所处的状态.其中t,join是为了让main线程等待t线程执行完毕后再继续执行,否则main方法可能会先执行完毕.
3.2 RUNNABLE和TIME_WAITING
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for(int i = 0;i<1000;i++){
}
});
System.out.println("线程执行之前:"+t.getState());
t.start();
//线程处于可执行状态
System.out.println("线程运行中:"+t.getState());
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程运行完:"+t.getState());
}
}
此处可以看见RUNNABLE,主要是因为我们当前线程的run方法里面没有sleep,join之类的方法,否则在后续打印中就不一定是RUNNABLE状态了.
如果在Thread里进行sleep操作,在main里使用循环进行获取状态操作.代码如下:
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for(int i = 0;i<1000;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
System.out.println("线程执行之前:"+t.getState());
t.start();
for(int i = 0;i<1000;i++){
System.out.println("线程运行中:"+t.getState());
}
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程运行完:"+t.getState());
}
}
就可能会出现这样的交替状态.当前获取到的状态,完全取决于系统的调度操作.(t线程是正在执行还是在sleep)
3.3 WAITING
public class ThreadDemo2 {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
Thread t1 = new Thread(()->{
for(int i = 0;i<1000;i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (obj){
obj.notify();
}
System.out.println("线程t1执行完毕!");
});
Thread t2 = new Thread(()->{
synchronized (obj){
try {
obj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
//此时t2没有调用start方法,是NEW
System.out.println("t2 start之前:"+t2.getState());
t2.start();
Thread.sleep(10);
//此时线程t2等待线程t1执行完毕,应该是WAITING状态
System.out.println("t2 wait中:"+t2.getState());
t1.join();
t2.join();
//此时t2执行完毕,TERMINATED
System.out.println("t2执行完成:"+t2.getState());
}
}
我们使用wait方法可以使线程出现WAITING状态.在上述代码中,我们使t2线程等待t1线程,当t1线程执行完毕之后,t2线程才开始执行.
3.4 BLOCKED
public class ThreadDemo3 {
public static void main(String[] args) throws InterruptedException {
Object obj1 = new Object();
Object obj2 = new Object();
Thread t1 = new Thread(()->{
synchronized (obj1){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (obj2){
}
}
});
Thread t2 = new Thread(()->{
synchronized (obj2){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (obj1){
}
}
});
t1.start();
Thread.sleep(100);
t2.start();
Thread.sleep(1500);
System.out.println(t2.getState());
t1.join();
t2.join();
}
}
BLOCKED是阻塞状态,死锁就可能会出现这种状态.在上述代码中,我们创建了两个线程,一个t1,一个t2,我们先让t1获取obj1,然后再获取obj2.然后让t2获取obj2,再获取obj1.这样就可以构成死锁.因为,当t1获取到obj1的时候,t1获取到了obj1锁,t2获取到了obj2锁,他们获取完毕之后.然后他们想要获取对方的锁,此时就构成了死锁.也就出现了BLOCKED状态.