Java线程状态

1. 线程状态在这里插入图片描述

  • 创建状态:当用new操作符创建一个线程时, 例如new Thread(),线程还没有开始运行,此时线程处在初始(新建)状态。

  • 就绪状态:也叫可运行状态,当前线程创建完毕通过start方法启动线程后,线程状态就由创建状态转为就绪状态了。但是当前线程不一定处于run方法,在操作系统的层面说当前线程已经获得了除CPU以外的所有资源。

  • 运行状态:当处在就绪状态的线程获得了CPU的使用时间,那么当前线程就从就绪状态转为运行状态,开始执行run方法体。

  • 阻塞状态:处于运行状态的线程突然被某种请求中断,那么就处于阻塞状态;例如:用户的IO请求,或者通过sleep方法让当前线程睡眠,或者被其他线程调用join方法抢占时执行,或者出现InterruptException异常等情况…

  • 死亡状态:当run方法执行完毕时线程自动死亡,或者存在一个未捕获的异常终止了run方法而使线程猝死。

  • 锁池队列:这个队列是针对同步问题延伸出来的,考虑到多线程的安全问题,临界区每次只能有一个线程访问(串行),当使用synchronized修饰符时当前的方法就是一个临界区,如果遇到多个线程需要访问这个临界区采用先来先到的原则,这些线程就会进入锁池队列排队等候。

  • 等待状态:当线程调用wait方法时该线程不会处于阻塞状态而是转为等待状态进入等待度列,等待状态的线程不会主动转为就绪状态,必须由其他线程调用notify() 或者 notifyAll()方法通知它结束等待否则将会一直等下去。

2. 常见线程状态方法


  1. start() 方法,处于创建状态的线程调用此方法后将会启动线程,从创建状态转为就绪状态。

  2. run() 方法,这是线程执行的方法体。线程执行时自动进入run方法执行。切记一定要通过start方法启动线程,否则单纯的调用run方法就是串行执行。

  3. sleep(long millis) 方法,当线程调用此方法时线程将会休眠,休眠时间为millis 毫秒,转为阻塞状态。当休眠时间完毕时转为就绪状态;sleep存在异常InterruptedException同时sleep每一个对象都有一个锁,sleep不会释放锁。

import java.text.SimpleDateFormat;
import java.util.Date;

/*
    1. sleep指定当前线程休眠的毫秒数,转入阻塞状态
    2. sleep存在异常InterruptedException
    3. sleep时间到达后线程进入就绪状态
    4. sleep可以模拟网络延时,倒计时等
    5. 每一个对象都有一个锁,sleep不会释放锁
 */
public class ThreadSleep implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            System.out.println(Thread.currentThread().getName()+" --- >"+i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Date date = new Date(System.currentTimeMillis());
        while(true){
            System.out.println(new SimpleDateFormat("hh:mm:ss").format(date));
            Thread.sleep(1000);
            date = new Date(System.currentTimeMillis());
        }
    }
}

  1. yield() 方法,让当前正在执行的线程暂停,但是不阻塞而是将当前线程转为就绪状态;让CPU重新调度,礼让不一定成功!只是当前线程让出了CPU,让所有线程重新竞争CPU,至于具体哪个线程被调度看CPU心情。
/*
    1. 礼让线程,让当前正在执行的线程暂停,但是不阻塞
    2. 将线程从运行状态转为就绪状态
    3. 让CPU重新调度,礼让不一定成功!看CPU心情
 */
public class ThreadYield 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) {
        Runnable r = new ThreadYield();
        new Thread(r,"a").start();
        new Thread(r,"b").start();
    }
}


  1. stop() 方法,由于该方法不安全现在已经弃用,建议手动设置让线程停止不建议使用此方法。
public class ThreadStop implements Runnable{
    private boolean flag = true;
    int i = 0;
    @Override
    public void run() {
        while(flag){
            System.out.println(Thread.currentThread().getName()+"---->"+i++);
        }
    }
    public void setFlag(boolean flag){
        this.flag = flag;
    }
    public static void main(String[] args) {
        ThreadStop t = new ThreadStop();
        Thread thread = new Thread(t);
        thread.start();
        for(int i = 0;i < 100;i++){
            if(i == 50){
                thread.stop();
            //    t.setFlag(false);
            }
            System.out.println("Main --> "+i);
        }
    }
}



  1. join() 方法,当某个线程调用此方法之后,其他线程进入阻塞状态,当前线程会一直执行完毕。可以理解为 “插队”
/*
    1. Join合并线程,待此线程执行完成后,再执行其他线程,其他线程进入阻塞状态
    2. 可以将Join方法想象为插队,将当前线程插队执行完再执行其他线程。
 */
public class ThreadJoin implements Runnable{
    public boolean flag = false;
    @Override
    public void run() {
        for(int i = 0;i < 50;i++){
            if(!flag){
                System.out.println(Thread.currentThread().getName()+"并行执行"+i);
            }
            else{
                System.out.println(Thread.currentThread().getName()+"来插队了" + i);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread = new Thread(threadJoin);
        thread.start();
        for(int i = 0;i < 100;i++){
            if(i == 88){			//88之前并行执行,88的时候强行插队执行完main再执行
                threadJoin.flag = true;
                thread.join();
            }
            System.out.println("Main --- > "+i);
        }
    }
}


  1. isAlive() 方法,用于判断当前线程是否死亡。如果返回值是true代表当前线程还存活,返回值为false代表当前线程死亡或者处于新建状态
import com.sun.xml.internal.ws.message.stream.StreamHeader;

public class ThreadLive implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i < 10;i++){		//执行时一直是存活状态
            System.out.println("run --- >"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadLive threadLive = new ThreadLive();
        Thread thread = new Thread(threadLive);
        System.out.println(thread.isAlive());           //新建状态   false
        thread.start();         //线程启动
        System.out.println(thread.isAlive());           //启动后   true
        thread.join();          //插队执行完毕,线程死亡
        System.out.println(thread.isAlive());           //线程死亡   false
        for(int i = 0;i < 10;i++){
            System.out.println("Main --- > "+i);
        }
    }
}


  1. interrupt() 方法,当 A 线程处于睡眠时,B 线程中可以通过A.interrupt()方法将处于休眠状态的 A 线程提前结束休眠,强行唤醒转为就绪状态等待CPU调度。被唤醒的线程会发生 InterruptException异常 ;例如:现在有一个学生一个老师,学生要睡一个小时后自动起来听课,但是老师喊了三声上课起立后学生必须醒过来。
public class ThreadInterrupt implements Runnable{
    private Thread student;
    private Thread teacher;

    public ThreadInterrupt() {
        student = new Thread(this,"学生");
        teacher = new Thread(this,"老师");
    }


    @Override
    public void run() {
        if(Thread.currentThread() == student){
            System.out.println("学生正在睡觉, 没有听课~");
            try {
                student.sleep(60*60*1000);      //睡一个小时在起来听课
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("学生睡好了, 开始认真听课!");
        }
        else if(Thread.currentThread() == teacher){
            for(int i = 1;i <= 3;i++){
                System.out.println("上课!");
                try {
                    teacher.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("班长: 起立!");
            student.interrupt();            //唤醒学生上课
        }
    }

    public static void main(String[] args) {
        ThreadInterrupt t = new ThreadInterrupt();
        t.student.start();          //开始睡觉
        t.teacher.start();          //开始上课
    }
}

3. 线程调度与优先级

  1. 处于就绪状态的线程首先进入就绪队列排队等候CPU调度,同一时刻在就绪队列中的线程可能有多个。Java虚拟机中的线程调度器负责管理线程,调度器把线程的优先级分为 10 个级别,分别用Thread类中的类常量表示。每个Java线程的优先级都在常数 1 ~ 10 之间,即Thread.MAX_PRIORITY 和 Thread.MIN_PRIORITY之间。如果没有明确设置线程的优先级别那么线程的优先级都为常数 5 ,即 Thread.NORM_PRIORITY。

  2. 线程的优先级可以通过 setPriority(int newPriority) 方法设置线程的优先级;如果接受的参数不在[1,10]的范围内,会抛出一个IllegalArgumenException异常;同时可以通过 getPriority() 方法返回线程的优先级。需要注意的是有些操作系统只认:1、5、10三个级别。

  3. 但是优先级高的不一定先执行,只能说优先级高的更加紧急抢到CPU的概率更大。所以优先级低的也有机会先执行,具体执行哪个还得CPU的心情。

public class ThreadSetPriority implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i < 10;i++){
            System.out.println(Thread.currentThread().getName()+" --- >"+i);
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadSetPriority(),"A");
        Thread t2 = new Thread(new ThreadSetPriority(),"B");
        Thread t3 = new Thread(new ThreadSetPriority(),"C");
        t1.setPriority(Thread.MAX_PRIORITY);			//优先级10
        t2.setPriority(Thread.MAX_PRIORITY);			//优先级10
        t3.setPriority(Thread.NORM_PRIORITY);			//优先级5
        t3.start();     t2.start();     t1.start();		
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值