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,谢谢~

posted @ 2020-11-25 15:59  Mike小菜鸡  阅读(552)  评论(0)    收藏  举报