Java多线程-线程的状态和基本线程API

100 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情

线程共有五大状态

1 创建

线程对象被创建就进入到新状态(new)

2 就绪

调用线程的start()方法,线程进入就绪状态

3 运行

线程进入运行状态,开始执行线程体代码

4 阻塞

调用sleep,wait等方法时,线程进入阻塞状态,线程不再继续往下执行,阻塞事件解除后,重新进入就绪状态,等待cpu调度执行

5 死亡

线程中断或者结束,一旦进入死亡状态,就不能再次启动线程

线程方法

1 停止线程

注意:

1 不推荐使用jdk提供的stop(),destroy()方法(已废弃)

2 推荐线程自己停下来

3 建议使用一个标志位进行终止变量,当flag=false时,则终止线程运行

package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  利用flag让线程停止

 *  @author:  魏一鹤

 *  @createDate:  2022-01-01 22:38

 **/



 //测试线程停止

 // 注意点

 // 1、建议线程正常停止---> 利用次数 不建议死循环(就算是死循环也要定义延时,不要跑的太快卡死cpu)

 // 2. 建议使用标志位 --->  设置一个标志位

 // 3. 不要使用stop或者destroy等过时或者jdk不建议使用的方法

public class TestThreadStop  implements Runnable{

    //1.定义一个标识符决定线程是否运行 true为运行 false为停止

  private boolean flag=true;

    @Override

    public void run() {

        int i=0;

        // true为运行 false为停止

  while (flag){

            System.out.println( "run....Thread" +i++);

        }

    }



    //2.定义一个方法转换标识符停止线程

  public void stopThread() {

        //false让线程停止

  this.flag=false;

    }



    public static void main(String[] args){

        //创建线程对象

 TestThreadStop testThreadStop = new TestThreadStop();

        //开启线程

  new Thread(testThreadStop).start();

        for (int i = 0; i < 1000; i++) {

            //主线程跑的次数

 System.out.println( "main:" +i);

            if(i==900){

                //线程运行900次让线程停止   调用stop方法切换标志位,让线程停止

 testThreadStop.stopThread();

                System.out.println( "线程该停止了" );

            }

        }

    }



}

2 线程休眠 sleep

  1. sleep(时间)指定当前线程阻塞的毫秒数(1000hs(毫秒)=1s(秒),一般一秒就够用)
  2. sleep存在异常interruptedException
  3. sleep时间达到后线程进入就绪状态
  4. sleep可以模拟网络延时,倒计时等
  5. 每一个对象都有一个锁,sleep不会释放锁(线程同步)

线程休眠的作用(模拟网络延时): 放大问题的发生性

买票

package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  线程休眠(阻塞) 模拟网络延时

 *  @author:  魏一鹤

 *  @createDate:  2022-01-02 20:13

 **/



 //模拟网络延时

 //作用    1 放大问题的发生性

public class TestThreadSleep implements Runnable  { 

  //票数

  int ticketNums=10;

    @Override

    public void run  () { 

  //火车票抢票

  while  (  true  ) { 

  //如果没票了就停止

  if  (  ticketNums<=0  ){ 

  break;

             } 

  //模拟延迟

  try  { 

 Thread.sleep  (  100  )  ;

             }  catch  (  InterruptedException e  ) { 

 e.printStackTrace  ()  ;

             } 

  //Thread.currentThread().getName() 获取当前线程名称 我们是可以给线程命名的

 System.out.println  (  Thread.currentThread  ()  .getName  ()  + "-->抢到了" +ticketNums--+ "张票"  )  ;

         } 

  } 

  public static void main  (  String  []  args  ){ 

  //创建runnable接口的实现类对象

 TestThreadSleep testThreadSleep = new TestThreadSleep  ()  ;

        //3个线程一起去抢票

        new Thread  (  testThreadSleep, "张三"  )  .start  ()  ;

        new Thread  (  testThreadSleep, "李四"  )  .start  ()  ;

        new Thread  (  testThreadSleep, "黄牛党"  )  .start  ()  ;



     } 

  } 

模拟倒计时

package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  模拟倒计时

 *  @author:  魏一鹤

 *  @createDate:  2022-01-02 20:22

 **/



public class TestThreadSleep2 {



    //倒计数方法

  public static void TimeDown() throws InterruptedException {

        //初始化秒数

  int timeNum=10;

        while (true){

            //线程休眠1s  1000ms=1s

 Thread.sleep(1000);

            //自减

 System.out.println(timeNum--);

            //倒到0时候停止

  if(timeNum==0){

                System.out.println( "倒计时结束!" );

                break;

            }

        }

    }

    public static void main(String[] args) throws InterruptedException {

        TimeDown();

    }

}

每1s获取当前系统时间

package com.wyh.thread;



import java.text.Format;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.SimpleTimeZone;



 /**

 *  @program:  Thread

 *  @description:  打印当前时间

 *  @author:  魏一鹤

 *  @createDate:  2022-01-02 20:32

 **/



public class TestThreadSleep3 {

    //打印当前系统时间

  public static void main(String[] args) throws InterruptedException {

        //获取当前系统时间

 Date date = new Date(System.currentTimeMillis());

      while (true) {

          Thread.sleep(1000);

          System.out.println( "当前时间:" +new SimpleDateFormat( "HH:mm:ss" ).format(date));

          //更新当前时间

 date=new Date(System.currentTimeMillis());

      }

    }

}

总结sleep的特点和作用

  1. 模拟网络延迟
  2. 倒计时
  3. sleep不会释放锁(线程同步)
  4. sleep存在异常interruptedException
  5. sleep时间达到后线程进入就绪状态
  6. sleep(时间)指定当前线程阻塞的毫秒数(1000hs(毫秒)=1s(秒),一般一秒就够用

3 线程礼让(yield)

  1. 礼让线程,让当前允许的线程暂停,但不阻塞

  2. 让线程从运行的状态转换为就绪状态

  3. 让cpu重新调度,礼让不一定会成功,看cpu心情!

package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  线程礼让

 *  @author:  魏一鹤

 *  @createDate:  2022-01-02 20:59

 **/



 //测试线程礼让 礼让不一定成功 只是让线程回到同一起跑线

public class TesThreadYield {

    public static void main(String[] args){

        //创建线程执行体

 ThreadYield threadYield=new ThreadYield();

        new Thread(threadYield, "线程A" ).start();

        new Thread(threadYield, "线程B" ).start();

    }

}

class ThreadYield implements Runnable{



    @Override

    public void run() {

        System.out.println(Thread.currentThread().getName()+ "开始执行" );

        //线程礼让

 Thread.yield();

        System.out.println(Thread.currentThread().getName()+ "结束执行" );

    }

}

4 线程强制执行(join)

  1. join合并线程,待此线程执行完成后,再开始执行其他线程,在此期间其他线程只能阻塞等待

  2. 可以把他想象成插队

  3. 需要被捕获异常InterruptedException

package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  线程join强制插队

 *  @author:  魏一鹤

 *  @createDate:  2022-01-03 21:27

 **/



 //线程join测试  可以把它想象成插队

public class TestThreadJoin 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 {

        //启动线程

 TestThreadJoin testThreadJoin = new TestThreadJoin();

        Thread thread = new Thread(testThreadJoin);

        thread.start();

        for (int i = 0; i < 500; i++) {

            //如果i==500 让run线程插队执行,main方法阻塞等待,等run方法执行完之后再执行

  if(i==200){

                thread.join();

            }

            System.out.println( "main启动线程" +i);

        }

    }

}

观察线程状态

首先回顾下之前的线程的五个状态

创建 等待 执行 阻塞 死亡

线程状态: thread.getState() ,Thread.state(是一个枚举类型 ) 线程key处于以下状态之一

Thread.State state = thread.getState();

pubic static enum Thread.state extends Enum<Thread.statu>

  1. NEW 尚未启动的线程处于此状态(新生状态)

  2. RUNNABLE 在Java虚拟机中执行的线程处于此状态 (运行状态)

  3. BLOCKED 被阻塞等待监视器锁定的线程处于此状态(阻塞状态)

  4. WAITING 正在等待另一个线程执行特定动作的线程处于此状态(阻塞状态)

  5. TIMED WAITING 正在等待另一个线程执行执行动作达到执行等待时间的线程处于此状态 (阻塞状态)

  6. TERMINATED 已退出的线程处于此状态 (终止状态)

 package com.wyh.thread;



 /**

 *  @program:  Thread

 *  @description:  测试观察线程性能状态

 *  @author:  魏一鹤

 *  @createDate:  2022-01-03 21:58

 **/



 //观察线程执行状态

public class TestThreadState {

    public static void main(String[] args) throws InterruptedException {

        //创建线程

 //使用lambda表达式简化代码  在Thread()中写入()->{代码体}

 Thread thread = new Thread(() -> {

            for (int i = 0; i < 5; i++) {

                //这里让线程阻塞(睡眠),时间为1000ms也就是1s,目的是便于观察

  try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

            System.out.println( "----------------------------" );

        });

        //观察线程状态



 //以上线程为新生状态 因为我们只是创建还没有调用

 Thread.State state = thread.getState();

        System.out.println( "线程state = " + state); //new



 //启动线程 观察启动后

 thread.start(); //

 state = thread.getState();

        System.out.println( "线程state = " + state); //run





 //线程跑起来有可能阻塞 有可能死亡,我们需要写个循环一直监听它



 //判断线程死亡 Thread.State.TERMINATED

 // 只要线程不终止 就一直输出状态

  while (state!=Thread.State.TERMINATED) {

            Thread.sleep(100);

            //更新线程状态

 state = thread.getState();

            System.out.println( "线程state = " + state); //run

 }



        //线程停止了之后不能再调用start()方法了 死亡之后的线程就不能再启动了  否则会报错

 //Exception in thread "main" java.lang.IllegalThreadStateException

 thread.start();





    }

}

死亡之后的

线程停止了之后不能再调用start()方法了 死亡之后的线程就不能再启动了 否则会报错

Exception in thread "main" java.lang.IllegalThreadStateException