线程的状态转换和调度
-
新建状态
New:新创建了一个线程对象 -
可运行状态
Runnable:线程对象创建后,其他线程调用了该对象的start()
方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。 -
运行状态
Running:可运行状态的线程获取了CPU资源时,执行程序run()
方法代码。 -
阻塞状态
Blocked:线程由于某种原因放弃CPU使用权,暂时停止运行。阻塞的情况分两种种:-
同步阻塞:对象的同步锁被其他的线程占用时,则JVM会把该线程放入锁池中等待锁释放。
-
其他阻塞:当运行的线程执行
sleep()
或join()
方法,或发起I/O请求时,该线程将进入阻塞状态。在此期间,线程不会释放已持有的锁,一旦sleep()
调用完成、join()
方法的等待线程终止或超时,或者 I/O 操作完成,线程将返回到可运行状态
-
-
Waiting(等待状态)
: 运行的线程执行wait()
方法,JVM会把该线程放入等待池中。需要被显式唤醒才能继续执行。 -
Timed Waiting(含等待时间的等待状态)
: 线程进入等待状态,但指定了等待时间,超时后会被唤醒 -
终止状态
(Terminated):线程正常完成了run()
方法执行流程 或 异常而提前退出时,该线程结束生命周期。
线程的调度
-
调整线程优先级:Java线程有优先级,且有继承关系(如A线程中创建B线程,AB优先级一样),优先级高的线程可能更先运行
static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。
-
线程睡眠:
Thread.sleep(long millis)
方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为可运行状态 ,sleep()
方法的实现是平台无关的,可以在不同的操作系统上正常工作 -
线程等待:调用
Object.wait()
方法,释放了当前线程持有的对象锁,并将线程放入等待池中,直到其他线程调用此对象锁(Object
)的notify()
或notifyAll()
方法唤醒 等待池中的一个或多个对象-
如果多个线程都在等待同一个对象锁,则
notify()
方法只会唤醒其中一个线程,而notifyAll()
则会唤醒所有等待中的线程,重新竞争该对象的锁
-
-
线程让步:调用
Thread.yield()
方法,让当前运行线程回到可运行状态,把执行机会让给自己,相同或者更高优先级的线程 -
线程加入:调用
Thread.join()
方法,可以让当前线程等待另一个线程的终止。即在当前线程中调用另一个线程的join()
方法,当前线程将会进入阻塞状态,直到另一个线程运行结束,然后恢复到可运行状态 -
线程唤醒:调用
Object.notify()
方法,可以唤醒一个在该对象上等待的线程。如果多个线程都在等待同一个监视器,则notify()
方法会随机选择一个线程来唤醒。。而notifyAll()
方法则会唤醒所有在该对象监视器上等待的线程,被唤醒的线程需要重新竞争对象锁才能继续执行。
例子说明
注意点
-
wait,notify和 notifyAll 只能在同步锁方法或者同步控制块里面使用,而sleep可以在任何地方使用
-
当线程离开一个同步块后,会自动释放该同步块持有的锁,这是Java规范
//wait用法
public class MyThreadPrinter2 implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThreadPrinter2(String name, Object prev, Object self) {this.name = name; this.prev = prev;this.self = self;}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (prev) { //先持有前一个线程所持有的对象锁前提下
synchronized (self) { //持有自身对象锁
System.out.print(name);
count--;
self.notify(); //唤醒一个在当前对象上等待的线程
}
//自动释放self锁
try {
prev.wait(); //释放prev对象锁,终止该锁上的当前线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);
//整体过程
//A线程最先运行,持有c,a对象锁-->唤醒B-->释放a锁-->释放c锁
//线程B持有a,b锁,执行同步代码块后-->唤醒C-->释放b锁-->释放a锁
//线程C持有b,c锁,执行同步代码块后-->唤醒A-->释放c锁-->释放b锁
new Thread(pa).start();
Thread.sleep(100); //确保按顺序A、B、C执行
new Thread(pb).start();
Thread.sleep(100);
new Thread(pc).start();
Thread.sleep(100);
}
}
//输出结果:
//ABCABCABCABCABCABCABCABCABCABC