上一篇文章咱们聊了多线程的基础内容,好比为何要使用多线程,线程和进程之间的不一样,以及建立线程的 4 种方式。本文已收录至个人 Github: https://github.com/xiaoqi6666/NYCSDEjava
今天咱们来讲一下线程的生命周期和经常使用 APIs:咱们须要很是清楚的知道线程的各类状态,好比排查程序运行慢的缘由时,就须要看下是否是哪里被阻塞了;另外它也是面试时很是喜欢问的,若是基础内容都答很差,恐怕直接就挂了。git
本文分为两大部分,github
关于线程的状态,网上各类说法都有,比较流行的是 5 种或者 6 种。关于 5 种状态的那个版本我没有找到理论依据,若是有小伙伴清楚的也欢迎留言指出。web
我这里所写的是根据 java.lang.Thread
的源码,线程有如下 6 大状态:面试
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITTING,
TIMED_WAITTING,
TERMINATED;
}
先上图,咱们再依次来看。安全
A thread that has not yet started is in this state.多线程
就是指线程刚建立,还没启动的时候,好比刚 new
了一个 thread
。编辑器
MyThread myThread = new MyThread();
A thread is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.ide
那么接下来,天然就是要启动线程了,也就是调用 thread
的 start()
方法。学习
myThread.start();
启动以后,线程就进入了 Runnable
状态。
此时全部的线程都会添加到一个等待队列里,等待“CPU 调度”。
若是抢占到 CPU 的资源,那就执行;若是没抢到,就等着呗,等当前正在执行的线程完成它能执行的时间片以后,再次抢占。
要注意这里在等待的通常是系统资源,而不是锁或者其余阻塞。
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 callingwait()
Object.
这里给出了很是明确的 use case
,就是被锁在外面的才叫阻塞。因此这里必需要有至少 2 个线程。
A thread in the waiting state is waiting for another thread to perform a particular action.
那具体有哪些缘由呢?
A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout Thread.join with no timeout LockSupport.park
因此说,当调用了
wait()
,
join()
,
park()
这里的等待状态是没有时间限制的,能够无限的等下去... 因此须要有人来唤醒:
wait()
进入等待状态的,须要有
notify()
或者
notifyAll()
方法来唤醒;
join()
进入等待状态的,须要等待目标线程运行结束。
好比在生产者消费者模型里,当没有商品的时候,消费者就须要等待,等待生产者生产好了商品发 notify()
。下一篇文章咱们会细讲。
致使这个状态的缘由以下:
Thread.sleep Object.wait with timeout Thread.join with timeout LockSupport.parkNanos LockSupport.parkUntil
其实就是在上一种状态的基础上,给了具体的时间限制。
那么当时间结束后,线程就解放了。
A thread that has exited is in this state.
这里有 3 种状况会终止线程:
stop()
方法,如今已经被弃用;
线程一旦死亡就不能复生。
若是在一个死去的线程上调用 start()
方法,那么程序会抛出 java.lang.IllegalThreadStateException
。
接下来咱们说说多线程中经常使用的 11 个 APIs。
join()
方法会强制让该线程执行,而且一直会让它执行完。
好比上一篇文章的例子是两个线程交替执行的,那么咱们这里该下,改为调用小齐线程.join()
,那么效果就是先输出 小齐666
。
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println("小齐666:" + i);
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new MyRunnable());
t.start();
t.join();
for(int i = 0; i < 100; i++) {
System.out.println("主线程" + i + ":齐姐666");
}
}
}
因此 join()
可以保证某个线程优先执行,并且会一直让它执行完,再回归到公平竞争状态。
join()
方法实际上是用 wait()
来实现的,咱们来看下这个方法。
wait()
其实并非 Thread
类的方法,而是 Object
里面的方法。
该方法就是让当前对象等待,直到另外一个对象调用 notify()
或者 notifyAll()
。
固然了,咱们也能够设定一个等待时长,到时间以后对象将会自动苏醒。
yield
自己的中文意思是屈服,用在这里倒也合适。
yield()
表示当前线程主动让出 CPU 资源一下,而后咱们再一块儿去抢。
注意这里让一下真的只是一下,从“执行中”回到“等待 CPU 分配资源”,而后全部线程再一块儿抢占资源。
顾名思义,这个方法就是让当前线程睡一会,好比说,
myThread.sleep(1000); // 睡眠 1 秒钟
它会抛出一个 InterruptedException
异常,因此还要 try catch
一下。
Returns a reference to the currently executing thread object.
该方法是获取当前线程对象。
注意它是一个 static
方法,因此直接经过 Thread
类调用。
好比打印当前线程
System.out.println(Thread.currentThread());
前文的例子中,它会输出:
Thread[Thread-0,5,main]
Thread[main,5,main]
没错,它的返回值也是 Thread
类型。
该方法能够获取当前线程名称。
这个名称能够本身设置,好比:
Thread t = new Thread(new MyRunnable(), "壹齐学");
该方法是获取线程的 Id
.
线程也有优先级的哦~
虽然优先级高的线程并不能百分百保证必定会先执行,但它是有更大的几率被先执行的。
优先级的范围是 1-10
,咱们来看源码:
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
若是不在这个范围,JDK 抛出 IllegalArgumentException()
的异常。
固然啦,咱们也是能够本身设置某个线程的优先级的。
设置的优先级也须要在规定的 1-10
的范围内哦,若是不在这个范围也会抛异常。
最后咱们来讲下 stop()
方法,也是前文提到过的强制中止线程的一种方式,但如今已被弃用,由于会引发一些线程安全方面的问题。
好了,以上就是有关线程状态和经常使用 API 的介绍了。相信你们看完以后对线程的整个流程应该有了清晰的认识,其实里面还有不少细节我没有展开,毕竟这是多线程的第 2 讲,更深刻的内容咱们慢慢来。
若是你喜欢这篇文章,记得给我点赞留言哦~大家的支持和承认,就是我创做的最大动力,咱们下篇文章见!
我是小齐,纽约程序媛,终生学习者,天天晚上 9 点,云自习室里不见不散!
**更多干货文章见个人 Github: https://github.com/xiaoqi6666/NYCSDE