JAVA线程的生命周期(以及操作线程的方法详解)

线程具有生命周期,其中包含5种状态,分别为出生状态、就绪状态、运行状态、暂停状态(包括休眠、等待和阻塞等)和死亡状态。

一、五种状态讲解

出生状态:就是线程被创建时的状态;

就绪状态:线程对象调用start()方法后,线程处于就绪状态(又称为可执行状态);

运行状态:当线程得到系统资源后就进入了运行状态,一旦进入运行状态,他会在就绪与运行状态下转换,同时也有可能进入暂停或死亡状态;

暂停(阻塞)状态:当线程调用sleep()方法、wait()方法或者发生阻塞时会进入暂停状态。当线程休眠结束、调用notify或notifyAll方法、或者阻塞结束时候,线程会重新进入就绪状态;

死亡状态;run方法执行完毕,或者发生错误异常时进入死亡状态,一旦进入死亡状态就不能再次启动;

在这里插入图片描述

二、操作线程的方法

操作线程有很多方法,这些方法可以使线程从某一种状态过渡到另一种状态。

1、线程的休眠

sleep()方法可以指定线程休眠的时间,线程休眠的时间以毫秒为单位。

由于sleep()方法有可能抛出InterruptedException异常,所以将sleep()方法放在try-catch块中。虽然sleep()方法的线程在一段时间会醒来,但是并不能保证他醒来后就会进入运行状态,只能保证他进入就绪状态。

扫描二维码关注公众号,回复: 13550695 查看本文章

代码示例:

利用sleep输出时间到秒

public static void main(String[] args) {
	Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
	while(true){
		try {
			Thread.sleep(1000);
			System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
			startTime = new Date(System.currentTimeMillis());//更新当前时间
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

输出结果:

2、线程的加入

假如当前程序为多线程程序,并且存在一个线程A,现在需要插入B线程,并要求B线程执行完之后再执行A,此时可以用join()方法来实现。这就好比A正在看电视,突然B上门收水费,A必须付完水费后才能继续看电视。

代码示例:

//join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
public class TestJoin implements Runnable{

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			System.out.println("线程VIP来了"+i);
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		TestJoin testJoin = new TestJoin();
		Thread thread = new Thread(testJoin);
		thread.start();
		
		for (int i = 0; i < 500; i++) {
			if(i == 200) {
				thread.join();//插队
			}
			System.out.println("main"+i);
		}
	}

}

输出结果:

3、线程的中断

以往会使用stop()方法停止线程,但是JDK早已废除了stop()方法,不建议使用stop()方法来停止线程。

这是我专门写的一篇关于线程停止的博客。

链接: https://blog.csdn.net/weixin_43888891/article/details/115291302

4、线程礼让

礼让线程,让当前正在执行的线程暂停,但不阻塞。
将线程从运行状态转为就绪状态。
让cpu重新调度,礼让不一定成功,看cpu心情。
礼让是调用Thread对象的yield()方法。

代码示例:

public class TestYield {
	public static void main(String[] args) {
		MyYield myYield = new MyYield();
		new Thread(myYield,"a").start();
		new Thread(myYield,"b").start();
	}
}

class MyYield implements Runnable{

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"线程执行开始");
		Thread.yield(); //礼让
		System.out.println(Thread.currentThread().getName()+"线程执行停止");
	}
	
}

输出结果:

5、观察线程状态

Thread对象的getState()方法可以查看线程状态。
*代码示例

public class TestState {
    
    
	public static void main(String[] args) throws InterruptedException {
    
    
		Thread thread = new Thread(()->{
    
    
			for (int i = 0; i < 5; i++) {
    
    
				try {
    
    
					Thread.sleep(1000);
					System.out.println(i);
				} catch (InterruptedException e) {
    
    
					e.printStackTrace();
				}
			}
		});
		
		//观察状态
		Thread.State state = thread.getState();
		System.out.println(state);
		
		//观察启动后
		thread.start();
		state = thread.getState();
		System.out.println(state);
		
		//只要线程不终止,就一直输出
		while (state != Thread.State.TERMINATED) {
    
    
			Thread.sleep(100);
			state = thread.getState();
			System.out.println(state);
		}
	}
}

输出结果:

6、设置线程优先级

Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程
线程调度器按照优先级决定应该调度哪个线程来执行
线程优先级用数字表示,范围从1-10
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度
Thread对象的setPriority(1)方法可以设置线程优先级

代码示例:

public class TestPriority {
	public static void main(String[] args) {
		//主线程默认优先级
		System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
		
		MyPriority priority = new MyPriority();
		Thread t1 = new Thread(priority);
		Thread t2 = new Thread(priority);
		Thread t3 = new Thread(priority);
		Thread t4 = new Thread(priority);
		Thread t5 = new Thread(priority);
		
		//先设置优先级,再启动
		t1.start();
		
		t2.setPriority(1);
		t2.start();
		
		t3.setPriority(4);
		t3.start();
		
		t4.setPriority(8);
		t4.start();
		
		t5.setPriority(9);
		t5.start();
	}
}

class MyPriority implements Runnable{

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
	}
	
}

输出结果:

7、守护线程

线程分为用户线程和守护线程;
虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕;
如后台记录日志,监控内存,垃圾回收等…
Thread对象的setDaemon(true)方法可以设置该线程为守护线程。

代码示例:

public class TestDaemon {
	public static void main(String[] args) {
		God god = new God();
		You you = new You();
		
		Thread thread = new Thread(god);
		//默认是false表示用户线程,正常的线程都是用户线程
		thread.setDaemon(true);
		thread.start();
		
		new Thread(you).start();
	}
}

class You implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 36500; i++) {
			System.out.println("好好活着");
		}
		System.out.println("goodbye!");
	}
}

class God implements Runnable{
	@Override
	public void run() {
		while(true) {
			System.out.println("上帝保佑着你");
		}
	}
}

输出结果:

这里有一点值得注意,主线程明明都走完了,而守护线程还在走,也就是他不随主线程走,就类似gc守护线程一样,虚拟机彻底关闭之后他才会关闭。

猜你喜欢

转载自blog.csdn.net/weixin_43888891/article/details/115363858