线程状态

    关于线程的状态,网上各种说法都有,比较流行的是 5 种或者 6 种。关于 5 种状态的那个版本我没有找到理论依据,如果有小伙伴清楚的也欢迎留言指出。

    我这里所写的是根据 java.lang.Thread 的源码,线程有以下 6 大状态:

    public enum State {
      NEW,
      RUNNABLE,
      BLOCKED,
      WAITTING,
      TIMED_WAITTING,
      TERMINATED;
    }

    先上图,我们再依次来看。

    1. New

    就是指线程刚创建,还没启动的时候,比如刚 new 了一个 thread

    MyThread myThread = new MyThread();

    2. Runnable

    那么接下来,自然就是要启动线程了,也就是调用 threadstart() 方法。

    myThread.start();

    启动之后,线程就进入了 Runnable 状态。

    此时所有的线程都会添加到一个等待队列里,等待“CPU 调度”。

    如果抢占到 CPU 的资源,那就执行;如果没抢到,就等着呗,等当前正在执行的线程完成它能执行的时间片之后,再次抢占。

    要注意这里在等待的一般是系统资源,而不是锁或者其他阻塞。

    3. Blocked

    这里给出了非常明确的 use case,就是被锁在外面的才叫阻塞。所以这里必须要有至少 2 个线程。

    4. Waiting

    那具体有哪些原因呢?

    所以说,当调用了

    这里的等待状态是没有时间限制的,可以无限的等下去... 所以需要有人来唤醒

    比如在生产者消费者模型里,当没有商品的时候,消费者就需要等待,等待生产者生产好了商品发 notify()。下一篇文章我们会细讲。

    5. Timed_waiting

    导致这个状态的原因如下:

    其实就是在上一种状态的基础上,给了具体的时间限制

    那么当时间结束后,线程就解放了。

    6. Terminated

    这里有 3 种情况会终止线程:

    线程一旦死亡就不能复生。

    如果在一个死去的线程上调用 start() 方法,那么程序会抛出 java.lang.IllegalThreadStateException

    接下来我们说说多线程中常用的 11 个 APIs。

    APIs

    1. join()

    join() 方法会强制让该线程执行,并且一直会让它执行完。

    比如上一篇文章的例子是两个线程交替执行的,那么我们这里该下,改成调用小齐线程.join(),那么效果就是先输出 小齐666

    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            for(int i = 0; i < 100; i++) {
                System.out.println("小齐666:" + i);
            }
        }

        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(new MyRunnable());
            t.start();
            t.join();

            for(int i = 0; i < 100; i++) {
                System.out.println("主线程" + i + ":齐姐666");
            }
        }
    }

    10 张图聊聊线程的生命周期和常用 APIs-LMLPHP

    所以 join() 能够保证某个线程优先执行,而且会一直让它执行完,再回归到公平竞争状态。

    join() 方法其实是用 wait() 来实现的,我们来看下这个方法。

    2. wait() and notify()

    wait() 其实并不是 Thread 类的方法,而是 Object 里面的方法。

    该方法就是让当前对象等待,直到另一个对象调用 notify() 或者 notifyAll()

    当然了,我们也可以设定一个等待时长,到时间之后对象将会自动苏醒。

    4. yield()

    yield 本身的中文意思是屈服,用在这里倒也合适。

    yield() 表示当前线程主动让出 CPU 资源一下,然后我们再一起去抢。

    注意这里让一下真的只是一下,从“执行中”回到“等待 CPU 分配资源”,然后所有线程再一起抢占资源。

    5. sleep()

    顾名思义,这个方法就是让当前线程睡一会,比如说,

    myThread.sleep(1000); // 睡眠 1 秒钟

    它会抛出一个 InterruptedException 异常,所以还要 try catch 一下。

    6. currentThread()

    该方法是获取当前线程对象。

    注意它是一个 static 方法,所以直接通过 Thread 类调用。

    比如打印当前线程

    System.out.println(Thread.currentThread());

    前文的例子中,它会输出:

    Thread[Thread-0,5,main]
    Thread[main,5,main]

    没错,它的返回值也是 Thread 类型。

    7. getName()

    该方法可以获取当前线程名称。

    这个名称可以自己设置,比如:

    Thread t = new Thread(new MyRunnable(), "壹齐学");

    8. getId()

    该方法是获取线程的 Id.

    9. getPriority()

    线程也有优先级的哦~

    虽然优先级高的线程并不能百分百保证一定会先执行,但它是有更大的概率被先执行的。

    优先级的范围是 1-10,我们来看源码:

        /**
         * The minimum priority that a thread can have.
         */

        public final static int MIN_PRIORITY = 1;

       /**
         * The default priority that is assigned to a thread.
         */

        public final static int NORM_PRIORITY = 5;

        /**
         * The maximum priority that a thread can have.
         */

        public final static int MAX_PRIORITY = 10;

    如果不在这个范围,JDK 抛出 IllegalArgumentException() 的异常。

    10. setPriority()

    当然啦,我们也是可以自己设置某个线程的优先级的。

    设置的优先级也需要在规定的 1-10 的范围内哦,如果不在这个范围也会抛异常。

    11. stop()

    最后我们来说下 stop() 方法,也是前文提到过的强制停止线程的一种方式,但现在已被弃用,因为会引起一些线程安全方面的问题。



    10 张图聊聊线程的生命周期和常用 APIs-LMLPHP

    本文分享自微信公众号 - 编码之外(ithuangqing)。
    如有侵权,请联系 [email protected] 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    09-14 13:46