Java多线程详解之二:线程5种状态及方法
一、线程状态

线程一共拥有以下五种状态:
1.创建状态:通过继承Thread类或者实现Runnable接口的方法新建一个线程类,然后new一个该线程类的对象;
2.就绪状态:线程类对象执行start()方法,可以使线程进入就绪队列,等待cpu资源(cpu时间片);
当处于就绪状态的线程获得cpu资源时,会进入运行状态,即执行该线程;
当处于运行状态的线程时间片用完后,会退回到就绪状态,等待cpu资源;
当处于阻塞状态的线程,阻塞解除时也会变成就绪状态,进入就绪队列;
3.运行状态:就绪状态的线程获得了cpu资源就成为了运行状态,执行程序体;
4.阻塞状态:线程因为某种原因放弃cpu使用权,除非解除阻塞,重新进入就绪状态,有三种阻塞情况:
(1)等待阻塞:运行的线程,执行wait()方法,系统会进入阻塞状态
(2)同步阻塞:运行的线程,在获取对象的同步锁时,若该同步锁被别的线程占用,则会进入阻塞状态
(3)其他阻塞:运行的线程执行sleep()方法或join()方法,或发出I/O请求,则线程进入阻塞状态
5.死亡状态:线程正常执行结束或者遇到异常,线程或进入死亡状态,线程不可以再次启动;
二、Java线程方法
1、停止线程
- stop()方法【不推荐使用】
- 使用标志位终止线程【推荐】
- interrupt()方法【推荐】
1.1 stop()方法【弃用】
(1)线程执行stop()方法,会立即终止run()方法,可能会导致一些清理性工作未能完成,比如数据库关闭等;
(2)执行stop()方法后,线程会立即释放持有的所有锁,可能会导致数据同步出现问题;
1.2 使用标志位终止线程【推荐】
在此方法中,给线程类定义一个flag标志位,如果标志位为true则线程可正常执行,然后构造一个终止线程方法,将flag设为false,这样线程就可停止执行。
public class TestFlag extends Thread{ //设置标志位 private boolean flag = true; @Override public void run() { //初始状态,flag为true,线程正常执行 while(flag){ //此处写入线程程序体 System.out.println(Thread.currentThread().getName()+"go"); } } //终止线程方法,将标志位设为false public void threadStop(){ this.flag = false; } public static void main(String[] args) { TestFlag t = new TestFlag(); t.start(); // t.threadStop(); } }
1.3 interrupt()方法【推荐】
interrupt方法并不是像break一样能立即终止循环,而是会设置一个标志位,告诉线程有人希望你中断,并不是真的停止线程。interrupt()方法具体介绍我会在下一篇文章中进行介绍~
2、线程休眠_sleep
sleep(t)方法会让当前线程进入阻塞状态,方法中的参数,即阻塞的时间。当阻塞时间结束后,线程会重新进入就绪状态。下面我们来使用sleep(t)方法,来写一个倒计时:
public class TestSleep implements Runnable{ //倒计时的时间 private int clock; //线程类构造方法 public TestSleep(int clock){ this.clock = clock; } @Override public void run() { for(int i = clock; i >= 0; i--){ System.out.println(i+"!"); try { //sleep方法单位为ms毫秒,所以1000等于1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("狼来啦!"); } public static void main(String[] args) { //创建实例对象 TestSleep thread = new TestSleep(10); new Thread(thread).start(); } }
注:sleep(int t)中参数单位为毫秒(ms),所以如果要设置为1秒,则sleep(1000).
2、线程礼让_yield
- 让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让cpu重新调度,礼让不一定成功!
public class TestYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"线程启动"); Thread.yield(); //当前线程转化为就绪状态 System.out.println(Thread.currentThread().getName()+"线程结束"); } public static void main(String[] args) { TestYield thread = new TestYield(); new Thread(thread,"A").start(); new Thread(thread,"B").start(); } }
3、线程强制执行_join
- 待此线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队,你们都在食堂排队打饭,突然一个人插到了第一位,你们必须等他打到饭,你们才能继续排队打饭,听起来太霸道了
public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 3; i++){ System.out.println("重要的事说三遍!我砖石王老五来插队了!"); } } public static void main(String[] args) throws InterruptedException { TestJoin thread = new TestJoin(); Thread t=new Thread(thread); //将该线程优先级设置低一点,便于观察 t.setPriority(1); t.start(); //此处是主线程 for(int i = 0; i < 100; i++){ if(i == 20){ t.join(); } System.out.println("main"+i); } } }
欢迎关注微信公众号,不定期分享学习笔记与资料,与Mike一起学java,谢谢~

浙公网安备 33010602011771号