积淀、分享、成长,让本人和别人都能有所播种!😄
一、Thread状态
Java
的线程状态形容在Thread
类外面的枚举类State
中,包门路为java.lang.Thread.State
,总共蕴含以下六种状态:NEW
、RUNNABLE
、BLOCKED
、WAITING
、TIMED_WAITING
、TERMINATED
public enum State {
// 尚未启动的线程的线程状态
NEW,
// 可运行线程的线程状态,是可运行的线程
// 这个状态在Java虚拟机中进行,但它可能期待来自操作系统的其余资源,比方处理器
RUNNABLE,
// 线程阻塞期待监视器锁的线程状态
// 处于阻塞状态的线程正在期待监视器锁
// 例如synchronized锁
BLOCKED,
// 期待线程的线程状态
// 线程调用以下办法会处于期待状态:Object.wait()不超时、Thread.join()不超时、LockSupport.park()
// 一个处于期待状态的线程正在期待另一个线程执行特定动作,例如:
// 一个线程调用了Object.wait()办法在一个对象上正在期待另一个线程调用Object.nofify()或者
// Object.nofifyAll()办法开启那个对象
// 一个调用了Thread.join()办法的线程正在期待指定线程终止
WAITING,
// 具备指定等待时间的期待线程的线程状态,调用一下办法会处于这个状态:
// Object.wait() 超时、Thread.join()超时
// LockSupport.parkNanos()、LockSupport.parkUntil()
TIMED_WAITING,
// 已终止线程的线程状态
// 线程已执行结束或者产生异样终止
TERMINATED
}
下面的六种状态相当于形容了一个线程的生命周期,这些状态之间是能够流转的,那么线程的状态是如何流转的呢,咱们看下图:
-
NEW
:未启动状态。public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; // 这个时候只是new了一个线程,并没有调用start()办法 // 输入 NEW System.out.println(t.getState().name()); }
-
RUNNABLE
:可运行状态,处于可运行状态的线程正在Java
虚拟机中运行,但也可能是正在期待来自操作系统资源,比方CPU。在RUNNABLE
状态中蕴含了RUNNING
、READY
两个状态,这两个状态是能够相互流转的。当线程调用start()
办法后,线程就处于READY
状态,期待操作系统调配CPU
工夫片,调配后进入RUNNING
状态。当调用yield()
办法后,只是谦让的容许以后线程让出CPU
,然而不肯定让,由操作系统决定,如果让了以后线程就会进入READY
状态,期待零碎调配CPU
工夫片再次进入RUNNING
状态。public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; t.start(); // 调用start()办法 // 输入RUNNABLE System.out.println(t.getState().name()); }
-
BLOCKED
:阻塞状态。当产生线程锁竞争状态下,没有获取到锁的线程会被挂起进入阻塞状态,比方synchronized
锁。public static void main(String[] args) throws InterruptedException { final Object lock = new Object(); Thread t = new Thread(){ @Override public void run() { synchronized (lock){ System.out.println(Thread.currentThread().getName()); } } }; // main线程先获取锁, t线程start的时候进入阻塞状态 synchronized (lock) { t.start(); Thread.sleep(1000); // 输入BLOCKED System.out.println(t.getState().name()); } }
-
WIITING
:期待状态,可被唤醒的期待状态,此时线程不会执行也不会被调度,:可被唤醒的期待状态,此时线程不会被执行也不会被系统调度,此状态能够通过 synchronized 取得锁,调用 wait 办法进入期待状态,最初通过Object.notify()
、Object.nofifyAll()
唤醒。下列办法能够让线程进入WAITING
状态:Object.wait()
、Thread.join()
、LockSupport.park()
,调用以下办法能够唤醒登台的线程进入RUNNABLE
状态:Object.notify()
、Object.nofifyAll()
、LockSupport.unpark(Thread)
。public static void main(String[] args) throws Exception { final Object lock = new Object(); Thread t = new Thread(){ @Override public void run(){ try { synchronized (lock) { lock.wait(); System.out.println(Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } }; t.start(); Thread.sleep(1000); synchronized (lock) { // 输入WAITING System.out.println(t.getState().name()); lock.notify(); } }
-
TIMED_WAITING
:具备等待时间的期待状态,此时线程不会执行也不会被调度,直到等待时间到期后才会被执行。下列办法能够让线程进入TIMED_WAITING
状态:Thread.sleep(long)
、Object.wait(long)
、Thread.join(long)
、LockSupport.parkNanos()
、LockSupport.parkUntil()
。除了等待时间到期会被执行外,还能够调用以下办法:Object.notify()
、Object.nofifyAll()
、LockSupport.unpark(Thread)
。public static void main(String[] args) throws Exception { Thread t = new Thread(() ->{ try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } }); t.start(); Thread.sleep(1000); // 输入TIMED_WAITING System.out.println(t.getState().name()); }
-
TERMINATED
:已终止状态,线程已实现执行或者产生了异样终止。public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }; t.start(); // 输入 TERMINATED System.out.println(t.getState().name()); }
二、创立Thread形式
创立线程的形式有三种,别离是:继承Thread
类、实现Runnable
接口、实现Callable
接口和应用Future
。
继承Thread
public class MyThread extends Thread {
@Override
public void run() {
// do something
}
}
实现Runnable
public class MyThread implements Runnable {
@Override
public void run() {
// do something
}
}
实现Callable接口和应用Future
public class ThreadDemo implements Callable {
@Override
public String call() {
return "str";
}
public static void main(String[] args) throws Exception {
ThreadDemo threadDemo = new ThreadDemo();
FutureTask<String> future = new FutureTask<String>(threadDemo);
Thread thread = new Thread(future);
thread.start();
System.out.println(future.get());
}
}
三、Thread办法应用
Thread
类罕用的办法有以下:
start()
:启动以后线程。run()
:线程启动的时候执行的办法。currentThread()
:静态方法,返回执行以后代码的线程。getName()
:获取以后线程的名字。setName(String name)
:设置以后线程的名字yield()
:开释以后CPU的执行权(但也有可能下一刻的执行权又回到了以后线程,主控权还是在CPU手上)。join()
:当线程a调用线程b的join()
办法,此时线程a进入阻塞状态,直到线程b齐全执行完之后,线程a完结阻塞状态。stop
:当执行此办法时,强制完结以后线程(已停用)。sleep()
:让以后线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒工夫内,以后过程是阻塞状态。getPriority()
:获取线程优先级。isAlive()
:判断以后线程是否存活(线程执行完之前都是存活的)。setDeamon()
:设置守护线程。isDaemon()
:是否是守护线程。isInterrupted()
:线程是否中断。
守护线程
守护线程又称后盾线程,默认创立进去的线程都是前台线程,能够通过setDeamon(true)
设定为后盾线程。
后盾线程和前台线程次要辨别在完结机会:当一个过程中的所有前台线程都执行结束,无论过程中的后盾线程是否执行结束,都要强制中断。
看以下例子:
public static void main(String[] args) {
Thread rose = new Thread(() ->{
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Rose:啊啊啊啊啊AAAAAaaaaa......");
System.out.println("成果:噗通......");
}
});
Thread jack = new Thread(() ->{
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("Jack:You jump,I jump");
}
});
// jack线程设置为后盾线程, 肯定要在start()办法之前调用
jack.setDaemon(true);
rose.start();;
jack.start();
//while(true);//有过程没完结,后盾线程不会完结。
}
下面代码输入如下:
Jack:You jump,I jump
Rose:Let me go die!
Rose:Let me go die!
Jack:You jump,I jump
Jack:You jump,I jump
Rose:Let me go die!
Jack:You jump,I jump
Rose:Let me go die!
Rose:Let me go die!
Jack:You jump,I jump
Jack:You jump,I jump
Rose:Let me go die!
Jack:You jump,I jump
Rose:Let me go die!
Jack:You jump,I jump
Rose:Let me go die!
Rose:Let me go die!
Jack:You jump,I jump
Jack:You jump,I jump
Rose:Let me go die!
Rose:啊啊啊啊啊AAAAAaaaaa......
成果:噗通......
从输入能够看出前台线程执行结束之后,后盾线程就立刻进行了,如果把while(true)
去掉正文,那么后盾线程会始终执行。
sleep
sleep()
办法能够使以后办法的线程阻塞指定毫秒,超时后,该线程办法会主动回到RUNNABLE
状态期待再次调配工夫片执行。
public static void main(String[] args) {
System.out.println("程序开始了");
try{
/*
* 这里会使main线程阻塞5秒,在此过程中
* 若其余线程调用了main线程的interrupt办法
* 试图中断main线程时,sleep办法会抛出异样
*/
Thread.sleep(5000);
}catch(InterruptedException e){
}
System.out.println("程序完结了");
}
join
join()
办法会阻塞调用以后办法的线程,并在join()
办法所属对象线程上期待,直到该线程执行结束才会解除阻塞继续执行。
举个栗子:a线程调用b线程的join()
办法,那么a线程就会进入阻塞状态,直到b线程执行结束才会解除阻塞持续往下执行。
public static void main(String[] args) {
// 下载图片线程
final Thread download = new Thread(() ->{
System.out.println("download:开始下载照片");
for (int i = 1; i <= 100; i++) {
System.out.println("下载进度:"+i+"%");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("download:图片下载结束");
});
// 显示图片线程
final Thread show = new Thread(() ->{
System.out.println("show:开始显示图片");
try {
// 只有图片下载结束之后能力显示图片
// 调用下载图片线程的join()办法阻塞显示图片线程直到图片下载结束
download.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("show:图片显示结束");
});
download.start();
show.start();
}
下面代码输入如下:
show:开始显示图片
download:开始下载照片
下载进度:1%
下载进度:...
下载进度:100%
download:图片下载结束
show:图片显示结束
wait & nofify
wait()
和notify()
办法是在Object
类定义的,用来协调线程同步应用,相比join()
同步的及时性更强,因为join()
办法必须期待另外一个线程的所有工作都完结。
public static boolean isFinish;
public static Object obj = new Object();
public static void main(String[] args) {
// 下载图片线程
final Thread download = new Thread(() ->{
System.out.println("download:开始下载照片");
for (int i = 1; i <= 100; i++) {
System.out.println("down图片进度:"+i+"%");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("download:图片下载结束");
isFinish = true;
// 图片下载结束就能够告诉显示图片线程显示图片, 没必要等下载附件执行结束
synchronized (obj) {
obj.notify();
}
// 开始下载附件
System.out.println("down:开始下载附件...");
for (int i = 1; i <= 100; i++) {
System.out.println("down附件进度:" + i + "%");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
System.out.println("down:附件下载结束!");
});
// 显示图片线程
final Thread show = new Thread(() ->{
System.out.println("show:开始显示图片");
try {
// obj.wait()办法会导致show线程进入阻塞状态直到obj调用notify()办法
synchronized (obj) {
obj.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!isFinish) {
throw new RuntimeException("图片不存在!");
}
System.out.println("show:图片显示结束");
});
download.start();
show.start();
}
下面输入如下:
show:开始显示图片
download:开始下载照片
down图片进度:1%
down图片进度:...
down图片进度:100%
download:图片下载结束
down:开始下载附件...
show:图片显示结束
down附件进度:1%
down附件进度:...
down附件进度:100%
down:附件下载结束!
从下面输入咱们看出当下载线程图片下载结束之后,显示图片线程就执行了,不须要期待附件下载结束再执行。
Oject
还有一个notifyAll()
办法,当该办法被调用时,期待队列中的所有对象都被会唤醒。
yield
yield()
办法会使线程让出CPU
,但不是暂停执行,线程还会持续进行CPU
的抢夺,然而也不是肯定就会让出,这个由操作系统决定。如果一个线程不那么重要,或者对应工作的优先级非常低,或者不心愿它占用过多的资源,那么就能够应用yield()
办法给予其它线程更多的执行机会。
sleep和wait的区别
- 被
wait()
办法阻塞的线程能够通过notify()
或者notifyAll()
办法唤醒,而执行sleep(0
办法的线程只能始终休眠到指定工夫,不可被唤醒。 - 当被
wait()
办法阻塞的线程被唤醒的时候,会开释指标对象的锁,而sleep()
办法指定的睡眠时候到的时候不会开释任何资源。
发表回复