Thread的几种状态以及sleep/yield/join/wait/notify/notifyAll方法的区别

线程状态

Java的Thread类中对线程的状态有如下定义:

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

NEW

Thread state for a thread which has not yet started.

尚未启动的线程的线程状态。

此时线程刚刚创建,并未调用start()方法启动。

Thread thread = new Thread();
System.out.println(thread.getState()); // NEW

RUNNABLE

Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

可运行线程的线程状态。 处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待来自操作系统的其他资源,例如处理器。

线程调用start()方法开始运行,这个状态下也会发生一些等待,一般等待的是其他系统资源,而不是锁、sleep等。

Thread thread = new Thread(() -> System.out.println(Thread.currentThread().getState())); // RUNNABLE
thread.start();

BLOCKED

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}.

线程的线程状态被阻塞等待监视器锁定。 处于阻塞状态的线程正在等待监视器锁定以在调用{@link Object#wait()Object.wait}之后输入同步块/方法或重新输入同步块/方法。

这种状态是在有多个线程有同步操作的场景,如下thread1虽然释放了CPU,但是没有释放people的锁,致使thread2进入了阻塞状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();

Thread thread2 = new Thread(() -> {
    synchronized (people) {

    }
});
thread2.start();

WAITING

Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

{@link Object#wait() Object.wait} with no timeout

{@link #join() Thread.join} with no timeout

{@link LockSupport#park() LockSupport.park}

A thread in the waiting state is waiting for another thread to perform a particular action.

For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.

等待线程的线程状态。 由于调用以下方法之一,线程处于等待状态:

Object.wait()

Thread.join()

LockSupport.park()

处于等待状态的线程正在等待另一个线程执行特定操作。

例如,在对象上调用Object.wait()的线程正在等待另一个线程调用 Object.notify()或Object.notifyAll()。 调用Thread.join()的线程正在等待指定的线程终止。

该状态下的线程处于等待状态,当另一线程唤醒这个线程时,线程立马进入就绪状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            people.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();

TIMED_WAITING

Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:

{@link #sleep Thread.sleep}

{@link Object#wait(long) Object.wait} with timeout

{@link #join(long) Thread.join} with timeout

{@link LockSupport#parkNanos LockSupport.parkNanos}

{@link LockSupport#parkUntil LockSupport.parkUntil}

具有指定等待时间的等待线程的线程状态。 由于在指定的正等待时间内调用以下方法之一,线程处于定时等待状态:

Thread.sleep

Object.wait(long)

Thread.join(long)

LockSupport.parkNanos

LockSupport.parkUtil

该状态的线程需要等待一些时间才能继续运行。WAITING状态是当发生某个事情才会进入就绪状态,TIMED_WAITING状态是当时间到达就会进入就绪状态。

Thread thread1 = new Thread(() -> {
    synchronized (people) {
        try {
            people.wait(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});
thread1.start();

TERMINATED

Thread state for a terminated thread. The thread has completed execution.

终止线程的线程状态。 线程已完成执行。

run()方法执行结束后,线程进入TERMINATED状态。

主要方法

wait()

wait()方法是Object的方法,是在资源的角度阻塞线程,也就是让线程放弃对资源的占用。

public static void main(String[] args) {
    People people = new People();

    // 线程一拿到对象的锁
    Thread thread1 = new Thread(() -> {
       synchronized (people) {
           System.out.println(1);
           try {
               // 对象调用wait方法使线程进入WAITING状态
 			   // people的锁被释放
               people.wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(2);
       }
    });
    thread1.start();

    // 线程二运行,拿到对象的锁
    Thread thread2 = new Thread(() -> {
       synchronized (people) {
           System.out.println(3);
       }
    });
    thread2.start();
}

运行结果:

1
3

因为线程一依旧处于阻塞状态,所以主线程main此时并没有结束运行。

sleep()

sleep()方法是线程的方法,是在线程的角度阻塞线程,无法操作对象锁,所以如果线程阻塞时锁住了某个对象,那么这个对象的锁将不会被释放。

public static void main(String[] args) {
    People people = new People();

    Thread thread1 = new Thread(() -> {
       synchronized (people) {
           System.out.println(1);
           try {
               // 线程调用sleep方法阻塞线程,线程进入TIMED_WAITING
               // 对象的锁没有被释放
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(2);
       }
    });
    thread1.start();

    // 线程二拿不到people的锁所以不能执行进入就绪状态
    Thread thread2 = new Thread(() -> {
       synchronized (people) {
           System.out.println(3);
       }
    });
    thread2.start();
}

运行结果:

1
2
3

两者的区别:

sleep()wait()
所属类不同Thread类的方法Object类的方法
时间不同必须指定时间可指定也可不指定时间
释放锁不同释放CPU执行权不释放锁释放CPU执行权释放锁
使用范围不同可以在任意地方使用只能在同步代码中使用

notify()

参考Java 源码–Object

notify()和notifyAll()方法唤醒被wait()方法置于WAITING状态的线程。notify()方法唤醒一个等待资源的线程,如果有多个线程同时等待一个资源,则由JVM选择一个线程唤醒,使其进入就绪状态,重新竞争锁。

public static void main(String[] args) {
    People people = new People();

    Thread thread1 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(1);
                // thread1进入WAITING状态
                // 释放锁
                people.wait();
                System.out.println(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread1.start();

    Thread thread2 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(3);
                people.wait();
                System.out.println(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread2.start();

    Thread thread3 = new Thread(() -> {
        synchronized (people) {
            System.out.println(5);
            // 唤醒一个等待people锁的线程
            people.notify();
            System.out.println(6);
        }
    });
    thread3.start();
}

运行结果如下,thread2被唤醒,thread1依旧处于WAITING状态。

1
3
5
6
4

notifyAll()

notifyAll()方法唤醒所有等待资源的线程。

public static void main(String[] args) {
    People people = new People();

    Thread thread1 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(1);
                people.wait();
                System.out.println(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread1.start();

    Thread thread2 = new Thread(() -> {
        synchronized (people) {
            try {
                System.out.println(3);
                people.wait();
                System.out.println(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread2.start();

    Thread thread3 = new Thread(() -> {
        synchronized (people) {
            System.out.println(5);
            // 唤醒所有等待people锁的线程
            people.notifyAll();
            System.out.println(6);
        }
    });
    thread3.start();
}

运行结果如下,thread1和thread2均被唤醒。

1
3
5
6
4
2

yield()

yield()方法把CPU让给同等优先级或更高优先级的线程。注意,其他线程不会立马进入运行状态,只是给其他线程提供竞争的机会。

public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
        System.out.println(1);
        Thread.yield();
        System.out.println(2);
    });
    thread1.setPriority(Thread.MIN_PRIORITY);
    thread1.start();

    Thread thread2 = new Thread(() -> System.out.println(3));
    thread2.setPriority(Thread.MAX_PRIORITY);
    thread2.start();
}

运行结果:

1
2
3

1
3
2

thread1礼让之后,thread1和thread2一起参与竞争,都有可能进入运行状态。疑惑?此处thread2的优先级已被设为最高了,为什么不一定是thread2先运行呢?

join()

join()方法会使当前线程等待调用join()方法的线程结束后才能继续执行。

public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
        try {
            Thread.sleep(10000);
            System.out.println("我刚睡醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    thread1.start();

    Thread thread2 = new Thread(() -> {
        try {
            System.out.println(1);
            thread1.join();
            System.out.println(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    thread2.start();
}

运行结果:

1
我刚睡醒
2
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值