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

线程状态

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

1
2
3
4
5
6
7
8
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}

NEW(新创建)

Thread state for a thread which has not yet started.

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

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

1
2
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等。

1
2
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进入了阻塞状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()的线程正在等待指定的线程终止。

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

1
2
3
4
5
6
7
8
9
10
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状态是当时间到达就会进入就绪状态。

1
2
3
4
5
6
7
8
9
10
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的方法,是在资源的角度阻塞线程,也就是让线程放弃对资源的占用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
2
1
3

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

sleep()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
1
2
3

两者的区别:

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

notify()

参考Java 源码–Object

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
2
3
4
5
1
3
5
6
4

notifyAll()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
2
3
4
5
6
1
3
5
6
4
2

yield()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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
2
3

1
2
3
1
3
2

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

join()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
3
1
我刚睡醒
2
-------------本文结束感谢您的阅读-------------

本文标题:Thread的几种状态以及sleep/yield/join/wait/notify/notifyAll方法的区别

文章作者:huihui

发布时间:2018年12月25日 - 00:12

最后更新:2019年02月14日 - 19:02

原始链接:http://101.200.47.120:8011/2018/12/25/Thread的几种状态以及sleepyieldjoinwaitnotifynotifyAll方法的区别/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。