【多线程】程序猿进阶多线程(三)—— 线程的运行状态
一、前言
在上一篇博客中,小编向大家介绍了 线程创建和启动,简单的向大家介绍了线程创建和启动的三种方法:1.继承Thread类,2.实现Runnable接口,3.使用Future和Task创建。可能大家对线程的初步创建有了一定的了解。
在这篇博客中,小编向大家介绍一下,线程运行起来后,有的状态。
二、线程的状态
线程在执行过程中,可以处于下面几种状态:
就绪(Runnable):线程准备运行,不一定立马就能开始执行。
运行中(Running):进程正在执行线程的代码。
等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。
阻塞状态(Blocked):等待 I/O 操作完成。
同步阻塞(Locking):等待获取锁。
死亡(Dead):线程完成了执行。
下面详细说明:
- 就绪状态 - Runnable
当我们创建好线程后,Thread t = new Thread();
,开始调用t.start();
方法后,线程就从初始状态转变为就绪状态。
就绪状态下的线程,在等待操作系统调用,操作系统会根据不同的调度算法来进行调度线程。比如操作系统使用时间片轮转算法。
- 运行状态 - Running
当操作系统选定要运行的线程后,这个线程就会从就绪状态转为运行状态。这个时候,运行状态的线程就会执行我们重写的run()
方法。
- 阻塞状态 - blocked
有的时候,我们需要给线程之间一些缓冲时间,通常使用Sleep()
让子线程和主线程错开。有的时候我们需要线程按照一定的顺序执行,这个时候我们可以使用b.join()
,安排在线程b执行完成后再执行。
所以在sleep()
和join()
调用的过程中,线程会处于阻塞状态。只有等sleep()
和join()
完成后,线程才会再次进入就绪状态,等待cpu调用。
- 等待状态 - waiting
运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒
- 锁池状态 - locking
当执行中的线程进入synchronized同步块的时候,没有获取到锁的线程,就会进入锁池状态,获取到锁的线程执行完成后,锁解除,进入就绪状态。
- 死亡状态 -dead
线程执行完成,进入死亡状态。
三、一些知识点
在上面的线程状态图中,里面有很多方法,可能不是很清楚。下面小编通过几个问题来对比记忆一下这些方法:
java多线程中,会有很多问题,比如经典的:
3.1 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
【方法一】
这个简单的问题,我们可以直接使用join函数完成,join的作用就是,b.join()
在b线程执行完成后再执行。这样就保证了执行顺序。
package com.dmsd.thread;
/**
* Created by Ares on 2018/6/11.
*
* 说明:使用join完成 ————t1执行完了,t2执行;t2执行完成后,t3执行。
*
* 假设现在有两个线程A、B。如果在A的run方法中调用B.join(),
* 表示A需要在B线程上面等待,也就是需要在B线程执行完成之后才能再次执行。
*/
public class join {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 run:"+i);
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(40);
t1.join();//表明当前线程需要在t1线程上等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2 run:"+i);
}
});
Thread t3 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(40);
t2.join();//表明当前线程需要在t2线程上等待
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t3 run:"+i);
}
});
t1.start();
t2.start();
t3.start();
}
}
【方法二】
可以说使用join的老铁,还是比较low的。在我们的juc包( java.util.concurrent)中,利用ExcutorService产生的newSingleThreadExecutor的单一线程池。这个线程池的底层是使用了先进先出的队列,通过submit依次把线程添加进队列,然后顺序执行。
package com.dmsd.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Ares on 2018/8/14.
*/
public class TestSingleThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Thread t1 = new Thread(new MyThread1());
Thread t2 = new Thread(new MyThread2());
Thread t3 = new Thread(new MyThread3());
executorService.submit(t1);
executorService.submit(t2);
executorService.submit(t3);
executorService.shutdown();
}
}
class MyThread1 implements Runnable {
@Override
public void run() {
System.out.println("I am thread 1");
}
}
class MyThread2 implements Runnable {
@Override
public void run() {
System.out.println("I am thread 2");
}
}
class MyThread3 implements Runnable {
@Override
public void run() {
System.out.println("I am thread 3");
}
}
底层中用了newThreadPoolExecutor()创建了线程池,线程池中一个线程,并把线程放到linkedBlockingQueue阻塞队列中。保证了线程的顺序执行。
源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
3.2 Java中sleep和wait的区别 ?
这个问题也是经常问的问题。
① 这两个方法来自 不同的类 分别是,sleep来自Thread类,和wait来自Object类。
sleep是Thread的静态类方法, 谁调用的谁去睡觉,即使在a线程里调用b的sleep方法,实际上还是a去睡觉, 要让b线程睡觉要在b的代码中调用sleep。
② 锁: 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。
③ 使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。
synchronized(x){
x.notify()
//或者wait()
}
四、小结
通过线程的状态,详细大家可以更加深入的剥开多线程的面纱,对多线程的理解也会更加的深刻。
上一篇: 【Java多线程】volatile关键字
下一篇: (恐怖)看的你出冷汗,发给你的女友试试