线程执行基本原理
我们要搞清楚线程是怎样被启动的,就需要先搞清楚CPU调度算法,操作系统的调度算法有很多,比如先来先服务(FIFO)、最短优先、时间片轮转等。
那么当调用线程的start()方法后,它具体做了什么呢?看下面这张图。
实际上,我们在将一个线程置为运行状态时,也就是调用start()方法时,在JVM和操作系统层面,JVM像操作系统发送了两个指令os:: create thread
和os:: start thread
操作系统根据调度算法来分配CPU资源用于执行这两个指令,执行完毕后回调JVM中的JavaThread::run
来用于执行run()方法。此时线程就从就绪状态(NEW)
变成了运行状态(RUNNABLED)
。
线程的状态
一般在java中,线程一共有6个状态:
- NEW:初始状态,线程被构建,但是还没有调用start()方法。
- RUNNABLED:运行状态,JAVA线程把操作系统中的就绪和运行两种状态统一称为“运行中”。
- 就绪状态,线程属于运行状态,但是还没有获取到CPU时间片。
- 运行中状态,线程属于运行状态,且获取到了CPU时间片,正在执行。
- BLOCKED:阻塞状态,表示线程进入了等待状态,线程因为某种原因放弃了对CPU的使用权,阻塞分为集中:
- 等待阻塞:线程执行wait()方法,jvm会把当前线程放入到等待队列
- 同步阻塞:线程在获取对象同步锁时,若该同步锁被其他线程锁占用了,那么jvm会把当前的线程放入到锁池
- 其他阻塞:运行的线程执行Thread.sleep或者t.join方法,或者发出了I/O请求时,JVM会把当前线程设为阻塞状态,当sleep结束、join线程终止、IO处理完毕则线程会恢复
- WAITING:等待状态
- TIME_WAITING:超时等待状态,超时自动返回
- TERMINATED:终止状态,表示当前线程执行完毕。
用一张图可以更清晰的理解线程生命周期
线程的中断
当其他线程调用当前线程的interrupt方法,表示向当前线程打个招呼,可以中断当前执行,至于当前线程中断后有什么操作由当前线程自己定。
比如:
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
}
}
});
thread.start();
Thread.sleep(100);
thread.interrupt();
}
//打印:
//执行
//interrupt
//执行
//执行
//执行
//...
上述代码中,main线程调用了thread.interrupt();
,thread线程进行了响应打印了interrupt,但是也仅仅是响应
,并没有影响thread线程的继续循环。侧面证明了,当前线程是否能够被中断,由自己决定,我可以回应你,但是回应后是否中断还是由我说的算。
如果想让当前线程收到外界的中断请求后就终止循环怎么办呢?
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("interrupt");
Thread.currentThread().interrupt();
}
}
}
});
thread.start();
Thread.sleep(100);
thread.interrupt();
}
//执行
//interrupt
在响应了外界的中断请求后,当前线程可以自己改变线程的interrupt状态,来终止while循环,停止线程的运行状态。