线程的生命周期和状态
最近学完了JAVA多线程实战的线程的生命周期和状态这一章,这一章主要讲述两点内容,分别是线程的生命周期和状态调度。接下来我将对这一章的内容进行总结。
一、线程的生命周期
线程和人、动物类似,都有生命周期。在线程的一个生命周期中,它具有五种状态,分别是:新建、就绪、运行、阻塞和死亡。如下图所示。
在线程启动以后,不会一直占用CPU,当存在多个线程时,CPU会在线程之间不断切换,得到CPU的线程会处在运行状态,而没有得到CPU的线程就处于阻塞状态。
具体说一下这五种状态:
- 新建状态:new一个线程对象
- 就绪:一个线程对象调用start()方法后,就处于就绪状态。就绪状态的线程还不能执行任务,只是具有执行任务的资格
- 运行:处于就绪状态的线程抢占到了CPU,开始执行run()方法。
- 注意:如果运行状态的线程还在运行中,CPU被其他线程抢走,那被抢走的线程就回到了就绪状态,继续等待抢占CPU
- 死亡:线程的run()方法执行结束,或者调用停止线程的方法,那线程就会死亡,变成垃圾
- 阻塞:当调用阻塞方法或者sleep()后,线程就会进入阻塞状态,不能执行任务,也不能准备抢夺CPU,就是没有执行任务的资格了,阻塞结束后会回到就绪状态,等待再次抢夺CPU
二.线程的睡眠
是线程睡眠的方法是Thread.sleep()。睡眠是令线程让出CPU最容易的方式,睡眠的时候线程让出CPU给其他线程,这样就能轮换执行任务。睡眠结束后,线程自动处于就绪状态,等待执行任务。
public class UserThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserThread ut1 = new UserThread();
UserThread ut2 = new UserThread();
ut1.start();
ut2.start();
//线程的执行顺序无法控制,但谁被sleep了,谁就会进入睡眠,也就进入了阻塞状态,停止执行任务,不占有CPU。
}
}
public class UserThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":A");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":B");
}
}
public class UserThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserThread ut1 = new UserThread();
UserThread ut2 = new UserThread();
ut1.start();
ut2.start();
//线程的执行顺序无法控制,但谁被sleep了,谁就会进入睡眠,也就进入了阻塞状态,停止执行任务,不占有CPU。
}
}
三、线程的让步
让步就是线程让出执行权的意思,线程可以把自己的执行权让给具有相同优先级的线程,自己回到就绪状态,调用让步方法yield()即可。但是要注意,让步只是礼让,并不能保证执行权一定会让出去,也有可能线程让出后又得到执行权了。
public class UserThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":A");
Thread.yield();
System.out.println(Thread.currentThread().getName()+":B");
}
}
public class UserThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserThread ut1= new UserThread();
UserThread ut2 = new UserThread();
ut1.start();
ut2.start();
}
}
四、线程的合并
合并的作用就是将并行的线程合并为一个线程执行。当一个线程需要等待另一个线程执行结束后才能执行时可以使用合并,合并方法为join()
public class UserThread extends Thread{
@Override
public void run() {
for(int i = 0;i<10;i++) {
System.out.println("线程1第"+i+"次执行");
}
}
}
public class UserThreadTest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Userthread ut = new Userthread();
ut.start();
// for(int i = 0;i<20;i++) {
// System.out.println("主线程第"+i+"次执行");
// }//这种情况下主线程和线程一互相抢夺资源,不一定谁输出
for(int i=0;i<20;i++) {
ut.join();//并行方法
System.out.println("主线程第"+i+"次执行");
}//子线程执行完主线程才会继续执行
}
}
五、守护线程
Java中有两种线程,分别是用户线程和守护线程。用户线程就是我们平时用来执行任务的线程,守护线程则是用户线程的保姆,当JAVA虚拟机中用户线程在工作时,守护线程就工作,用户线程都结束工作后,守护线程会随着JAVA虚拟机退出而结束。JVM的垃圾回收,内存管理等现成都是守护线程。调用线程对象的方法setDaemon(true),可将线程设置为守护线程。该方法必须在启动线程前调用。
public class UserThread1 extends Thread{
@Override
public void run() {
for(int i=0;i<5;i++) {
System.out.println("线程1第"+i+"次执行");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class UserThread2 extends Thread{
@Override
public void run() {
for(int i = 0;i<99999;i++) {
System.out.println("后台线程第"+i+"次执行");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Tset {
public static void main(String[] args) {
// TODO Auto-generated method stub
UserThread1 ut1 = new UserThread1();
UserThread2 ut2 = new UserThread2();
ut2.setDaemon(true);
ut1.start();
ut2.start();//线程1结束后,后台线程也结束
}
}
六、线程的中断和死亡
线程中断就是让目标线程停止任执行,但是不会是线程立即终止,而是给线程发一个通知,告诉它JVM希望它停止,但是线程何时退出,由线程自己决定。
public class Test {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Thread thread = new Thread() {
@Override
public void run() {
while(true) {
//判断当前线程是否中断
if(this.isInterrupted()) {
System.out.println("==true==");
break;
}
}
}
};
thread.start();
Thread.sleep(5000);
thread.interrupt();
}
}
- 点赞
- 收藏
- 关注作者
评论(0)