一、start方法
对于线程的Thread类有个核心的方法叫做start()
,其底层调用了start0()
这个native方法。
想要继续深入了解start0
干了什么事情,我们就需要下载一个OpenJDK
openjdk中写JNI一般是一一对应的,Thread.java对应的就是Thread.c(位于openjdk8\jdk\src\share\native\java\lang
目录下),此时查看源码可以看到在jvm.h
中找到了声明
继续读jvm.cpp文件(openjdk8\hotspot\src\share\vm\prims
)中的JVM_StartThread方法
通过阅读上面的方法,我们看到了关键性的调用Thread::start(native_thread)
,所以我们需要继续往下追,看thread.cpp文件(位于openjdk\hotspot\src\share\vm\runtime
目录下),经过分析源码包括注释内容,我们发现其实最底层是由操作系统来分配线程。
二、interrupt方法
什么是中断机制?
1.一个线程不应该由其他线程来强制中断或停止,而是应该山线程自己自行停止,自己来决定自己的命运。所以,Thread.stop,Thread.suspend, Thread.resume都已经被废弃了。在Java中没有办法立即停止一条线程,然而停止线程却显得尤为重要,如取消一个耗时操作。因此,Java提供了一种用于停止线程的协商机制―—中断,也即中断标识协商机制。
2.若要中断一个线程,你需要手动调用该线程的interrupt方法,该方法也仅仅是将线程对象的中断标识设成true;接着你需要自己写代码不断地检测当前线程的标识位,如果为true,表示别的线程请求这条线程中断。
3.每个线程对象中都有一个中断标识位,用于表示线程是否被中断;该标识位为true表示中断,为false表示未中断;通过调用线程对象的interrupt方法将该线程的标识位设为true;可以在别的线程中调用,也可以在自己的线程中调用。
Thread类中的三个Interrupt方法:
1.源码分析
interrupt分析:
①如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,不受影响。所以,interrupt()并不能真正的中断线程,需要被调用的线程自己进行配合才行。
②如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。
isInterrupted:
interrupted:
可以发现上面两个方法的本质是一样的!clearInterrupted为true就会清理线程的中断标志位!
2.如何停止中断运行中的线程?
以下列举了三种方法!
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class InterruptTest {
static volatile boolean bool = false;
static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
public static void m1() throws InterruptedException {
new Thread(()->{
while (true) {
if (bool){
System.out.println("interrupt.....");
break;
}
System.out.println("哦嗷嗷嗷");
}
},"A").start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
bool = true;
},"B").start();
}
public static void m2() throws Exception{
new Thread(()->{
while (true) {
if (atomicBoolean.get()){
System.out.println("interrupt.....");
break;
}
System.out.println("哦嗷嗷嗷");
}
},"A").start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
atomicBoolean.set(true);
},"B").start();
}
public static void m3() throws Exception{
Thread a = new Thread(() -> {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("interrupt.....");
break;
}
System.out.println("aaaaaa");
}
}, "A");
a.start();
TimeUnit.MICROSECONDS.sleep(20);
new Thread(()->{
a.interrupt();
},"B").start();
}
public static void main(String[] args) throws Exception {
// m1();
// m2();
m3();
}
}
3.当前线程中断标识为true,是不是线程就立即停止?
不是!!!证明如下
public class ThreadFlag {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 1; i <= 300; i++) System.out.println("---:" + i);
}, "t1");
t1.start();
System.out.println("t1线程默认的中断标识:"+t1.isInterrupted());
try { TimeUnit.MILLISECONDS.sleep(2);}catch (InterruptedException e) {e.printStackTrace();}
t1.interrupt();//设置标识为true
System.out.println("t1线程调研员interrupt后的中断标识为"+t1.isInterrupted() );
//以下结果为false!!!!!!!!!!!!!!
try { TimeUnit.SECONDS.sleep(2);}catch (InterruptedException e) {e.printStackTrace();}
System.out.println("由于打印完毕,变成了不活跃的线程:"+t1.isInterrupted() );
}
}
4.InterruptException报错的解决
如果线程处于被阻塞状态(例如处于sleep, wait, join 等状态),在别的线程中调用当前线程对象的interrupt方法,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常。
以下代码如果不在t1线程中加上 Thread.currentThread().interrupt();
这一行,程序就会一直打印hello永不停止!
public class Example {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
while (true) {
if(Thread.currentThread().isInterrupted()){
System.out.println("中断标识为true,程序停止!!!!");
break;
}
try {
Thread.sleep(20);
}catch (InterruptedException e) {
Thread.currentThread().interrupt();//不加这一行程序就会一直运行
e.printStackTrace();
}
System.out.println("hello");
}
},"t1");
t1.start();
try { TimeUnit.SECONDS.sleep(1);}catch (InterruptedException e) {e.printStackTrace();}
new Thread(()->{ t1.interrupt(); },"t2").start();
}
}