目录:
- 1、线程6种状态:
- 1.1、触发--->BLOCKED状态方法;
- 1.2、触发--->TIMED_WAITING状态方法;
- 1.3、触发--->WAITING状态方法;
- 2、线程启动方式:
- 3、线程中断:
- 3.1、kill -9 pid
- 3.2、suspend()、resume()方法
- 3.3、标志位退出
- 3.4、interrupte()
- 4、Thread.interrupte()对线程的影响
- 4.1 Thread.isInterrupted()、Thread.interrupted()作用
- 5 、源码分析:
- 5.1、isInterrupted()、interrupted()分析
- 5.2、interrupte()分析
1、线程6种状态:
ThreadStatus:
状态 | 含义 | 触发条件 |
---|---|---|
NEW | 就绪 | new Thread() |
RUNNABLE(READY) | 运行中 | new Thread().start() |
BLOCKED | 1、同步阻塞 | 锁争夺,导致等待 |
2、其他阻塞 | Thread.sleep() 或者 t.join() 或者 发出了 I/O 请求 | |
WAITING | 3、等待阻塞 | Thread.wait()方法,jvm 会把当前线程放入到等待队列中。 |
TIMED_WAITING | 等待(带有超时时间) | 超时时间达到后,自动返回 |
TERMINATED | 终止状态 | 当前线程执行完毕 |
1.1、触发--->BLOCKED状态方法:
- Synchronized修饰实例方法,加对象锁🔐;
- Synchronized修饰类,加类锁🔐;
- Synchronized修饰代码块,加锁🔐;
######1、对象锁
/**
* @author biudefu
* @since
*/
public class SynchronizeMain {
public static void main(String[] args) throws InterruptedException {
SynchronizeMain synchronizeMain = new SynchronizeMain();
// @001 对象锁
new Thread(synchronizeMain::testInstanseBlocked, "test-thread-blocked-instance-A").start();
Thread.sleep(TimeUnit.SECONDS.toMillis(3));
new Thread(synchronizeMain::testInstanseBlocked, "test-thread-blocked-instance-B").start();
// @002 类锁
new Thread(SynchronizeMain::testClassBlocked, "test-thread-blocked-class-C").start();
Thread.sleep(TimeUnit.SECONDS.toMillis(3));
new Thread(SynchronizeMain::testClassBlocked, "test-thread-blocked-class-D").start();
System.out.println("main线程 退出!");
}
private synchronized static void testClassBlocked() {
System.out.println(Thread.currentThread().getName() + ",获得类锁-开始运行!");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(300));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ",获得类锁 退出!");
}
private synchronized void testInstanseBlocked() {
System.out.println(Thread.currentThread().getName() + ",获得对象锁-开始运行!");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(300));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ",获得对象锁 退出!");
}
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):
"Attach Listener" #15 daemon prio=9 os_prio=31 tid=0x00007f836585a000 nid=0x5703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DestroyJavaVM" #14 prio=5 os_prio=31 tid=0x00007f83688ce800 nid=0x2503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"test-thread-blocked-class-D" #13 prio=5 os_prio=31 tid=0x00007f836889e000 nid=0xc07 waiting for monitor entry [0x000070000331e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain.testClassBlocked(SynchronizeMain.java:29)
- waiting to lock <0x000000076abb2650> (a java.lang.Class for com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain$$Lambda$4/1607521710.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-blocked-class-C" #12 prio=5 os_prio=31 tid=0x00007f836789c000 nid=0xa603 waiting on condition [0x000070000321b000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain.testClassBlocked(SynchronizeMain.java:32)
- locked <0x000000076abb2650> (a java.lang.Class for com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain$$Lambda$3/1828972342.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-blocked-instance-B" #11 prio=5 os_prio=31 tid=0x00007f8368a0d000 nid=0xa803 waiting for monitor entry [0x0000700003118000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain.testInstanseBlocked(SynchronizeMain.java:43)
- waiting to lock <0x000000076abb4a78> (a com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain$$Lambda$2/1480010240.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-blocked-instance-A" #10 prio=5 os_prio=31 tid=0x00007f8368a0a000 nid=0x5503 waiting on condition [0x0000700003015000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain.testInstanseBlocked(SynchronizeMain.java:46)
- locked <0x000000076abb4a78> (a com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
at com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain$$Lambda$1/999966131.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
下面例子侧面反映了Thread.Sleep(long) 不会释放当前线程持有的锁🔐。
通过jstack日志发现对象锁🔐和类锁🔐区别:
对象锁🔐阻塞:
waiting to lock <0x000000076abb4a78> (a com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
类锁锁阻塞:
waiting to lock <0x000000076abb2650> (a java.lang.Class for com.lyc.jvm.concurrent.thread.threadstatus.blocked.SynchronizeMain)
1.2、触发--->TIMED_WAITING状态方法:
- Thread.sleep(long);
- Object.wait(long);
- Thread.join(long);
- LockSupport.parkNanos(long);
- LockSupport.parkUntil(long);
/**
* @program: jvmproject
* @description: 线程状态集合demo
* @author: biudefu
* @create: 2019-08-23
**/
public class TestThreadAllStatus {
private static final long millis = 2000 * 1000;
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
ObjectTimedWaittingMain waittingMain = new ObjectTimedWaittingMain();
// @@1 wait(long)
new Thread(() -> {
testWait(waittingMain,millis);
}, "test-thread-timed_WAITING").start();
// @@2 sleep(long)
new Thread(() -> {
testSleep(millis);
}, "test-thread-timed_SLEEP").start();
// @@3 LockSupport.parkNanos(long);
new Thread(() -> {
testLockSupportNanos(millis*1000*1000);
}, "test-thread-timed_LockSupport_Nanos").start();
// @@4 LockSupport.parkUntil(long);
new Thread(() -> {
DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date myDate2 = dateFormat2.parse("2020-08-26 06:49:00");
testLockSupportUntil(myDate2.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
}, "test-thread-timed_LockSupport_Until").start();
// @@5 join(long)
Thread joinThread = new Thread(() -> {
testJoin();
}, "test-thread-timed_JOIN");
joinThread.start();
joinThread.join(millis);
System.out.println("main线程 退出!");
}
private static void testLockSupportUntil(long untilTimes) {
System.out.println("run-locksupport-Until-start:");
LockSupport.parkNanos(untilTimes);
System.out.println("run-locksupport-Until-end!");
}
private static void testLockSupportNanos(long nanos) {
System.out.println("run-locksupport-Nanos-start:");
LockSupport.parkNanos(nanos);
System.out.println("run-locksupport-Nanos-end!");
}
private static void testJoin() {
System.out.println("run-join-start:");
for (int i = 0; i < 99999999; i++) {
System.out.println("out-print-ln:" + i);
}
System.out.println("run-join-end!");
}
private static void testSleep(long sleepTimes) {
try {
Thread.sleep(sleepTimes);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void testWait(ObjectTimedWaittingMain waittingMain,long waitingTimes) {
try {
synchronized (waittingMain) {
waittingMain.wait(waitingTimes);
}
System.out.println("test-thread-timed_waitting,超时 退出!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):
"Attach Listener" #16 daemon prio=9 os_prio=31 tid=0x00007f944188f800 nid=0x1207 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"test-thread-timed_JOIN" #15 prio=5 os_prio=31 tid=0x00007f9443039800 nid=0xa103 runnable [0x000070000c468000]
java.lang.Thread.State: RUNNABLE
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
- locked <0x00000006c003e598> (a java.io.BufferedOutputStream)
at java.io.PrintStream.write(PrintStream.java:482)
- locked <0x00000006c00086c0> (a java.io.PrintStream)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
- locked <0x00000006c0008678> (a java.io.OutputStreamWriter)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.newLine(PrintStream.java:546)
- eliminated <0x00000006c00086c0> (a java.io.PrintStream)
at java.io.PrintStream.println(PrintStream.java:807)
- locked <0x00000006c00086c0> (a java.io.PrintStream)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.testJoin(ObjectTimedWaittingMain.java:80)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.lambda$main$4(ObjectTimedWaittingMain.java:55)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain$$Lambda$5/883049899.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-timed_LockSupport_Until" #14 prio=5 os_prio=31 tid=0x00007f94418b5800 nid=0xa303 waiting on condition [0x000070000c365000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.testLockSupportUntil(ObjectTimedWaittingMain.java:67)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.lambda$main$3(ObjectTimedWaittingMain.java:47)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain$$Lambda$4/1922154895.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-timed_LockSupport_Nanos" #13 prio=5 os_prio=31 tid=0x00007f94418b4800 nid=0xa403 waiting on condition [0x000070000c262000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.testLockSupportNanos(ObjectTimedWaittingMain.java:73)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.lambda$main$2(ObjectTimedWaittingMain.java:39)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain$$Lambda$3/495053715.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-timed_SLEEP" #12 prio=5 os_prio=31 tid=0x00007f9441839800 nid=0x5603 waiting on condition [0x000070000c15f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.testSleep(ObjectTimedWaittingMain.java:88)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.lambda$main$1(ObjectTimedWaittingMain.java:34)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain$$Lambda$2/189568618.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"test-thread-timed_WAITING" #11 prio=5 os_prio=31 tid=0x00007f9441843800 nid=0xa703 in Object.wait() [0x000070000c05c000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c00103a0> (a com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.testWait(ObjectTimedWaittingMain.java:98)
- locked <0x00000006c00103a0> (a com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.lambda$main$0(ObjectTimedWaittingMain.java:29)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain$$Lambda$1/1867083167.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007f9441805000 nid=0x3203 in Object.wait() [0x000070000b741000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c00106b8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x00000006c00106b8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007f9442810800 nid=0x3103 in Object.wait() [0x000070000b63e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c00089a8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000006c00089a8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
Locked ownable synchronizers:
- None
"main" #1 prio=5 os_prio=31 tid=0x00007f943f019000 nid=0x2603 in Object.wait() [0x000070000ac20000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c00084d8> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1260)
- locked <0x00000006c00084d8> (a java.lang.Thread)
at com.lyc.jvm.concurrent.thread.threadstatus.timedwatting.ObjectTimedWaittingMain.main(ObjectTimedWaittingMain.java:58)
Locked ownable synchronizers:
- None
通过demo发现:
- 1、joinThread.join(millis); 方法只会造成main主线程是TIME_WAITING状态,joinThread是Runnable状态。
-2、wait(long)方法,需要获取对象锁🔐
1.3、触发--->WAITING状态方法:
与触发TIMED_WAITING方法类似,只是去掉超时时间;
2、线程启动方式:
- 继承Thread类
- 实现Runnable接口
- 使用线程池
3、线程中断:
- 1、Thread.stop() == kill -9 pid // 不建议暴力⏹停止线程。
- 2、Thread.stop(),Thread.suspend() / Thread.resume(); //@Deprecated 弃用方法。
- 3、标志位退出。(因此这种终止线程的做法显得更加安全和优雅)
public class CancelThreadMain {
private static volatile boolean isCancelled;
/**
* 采用标志位(flag)方式,进行线程退出
*
* @throws InterruptedException
*/
private static void cancelThreadByFlagService() throws InterruptedException {
new Thread(() -> {
while (!isCancelled) {
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + ",running!");
}
}, "test-thread-flag-cancel").start();
TimeUnit.SECONDS.sleep(3);
cancel();
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + ",执行了cancel方法!");
}
private static void cancel() {
isCancelled = true;
}
public static void main(String[] args) throws InterruptedException {
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + ",主线程run!");
cancelThreadByFlagService();
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + ",主线程stop!");
}
}
执行结果:
2020-03-29 12:25:08,test-thread-flag-cancel,running!
2020-03-29 12:25:08,test-thread-flag-cancel,running!
2020-03-29 12:25:08,test-thread-flag-cancel,running!
2020-03-29 12:25:08,main,执行了cancel方法!
2020-03-29 12:25:08,main,主线程stop!
Process finished with exit code 0
- 4、Thread提供了interrupte()方式:
/**
* 通过Thread自带interrupt方法进行,线程退出,重点:没有throw InterruptedException,线程状态被修改为中断。
* @throws InterruptedException
*/
private static void interruptiMethodService() throws InterruptedException {
Thread thread = new Thread(() -> {
int i = 0;
//默认情况下, isInterrupted 返回--->false、通过 thread.interrupt 变成了--->true
while (!Thread.currentThread().isInterrupted()) {
i++;
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + "running!param:" + i);
}
System.out.println(DateUtil.getNowYYMMDDHHMMSS() + Thread.currentThread().getName() + ",thread isInterrupted:" + Thread.currentThread().isInterrupted() + ",Num:" + i);
}, "test-thread-interrupt-nomal");
thread.start();
TimeUnit.SECONDS.sleep(5);
thread.interrupt(); //加和不加的效果
}
4、Thread.interrupte()对线程的影响
Thread提供与中断相关的三个方法:
Thread.interrupte()、Thread.isInterrupted()、Thread.interrupted()。
3.1、Thread.interrupt(); 中断运行的线程,
线程 | 线程状态 | 执行动作 | 影响 | 获取interrupte状态 |
---|---|---|---|---|
Thread处于业务处理中 | RUNNIABLE | Thread.interrupte() | JVM中osThread的_interrupted属性置成true。 | Thread.isInterrupted()->true |
Thread处于sleep or wait | WAITTING(sleeping) |
Thread.interrupte() |
JVM会抛出InterruptedException异常到应用层。 JVM中osThread的_interrupted属性 依然是false 。 |
Thread.isInterrupted()->false |
Thread处于Synchronized锁争夺导致 | BLOCKED(on object monitor) | Thread.interrupte() | JVM会唤醒thead做锁争夺。 JVM中osThread的_interrputed 状态受影响,变成true |
Thread.isInterrupted()->true |
Thread处于执行了LockSupport.park() | WAITTING(park) | Thread.interrupte() | JVM不做唤醒, JVM中osThread的_interrputed 状态受影响,变成true |
Thread.isInterrupted()->true |
3.2、thread.isInterrupted();
此方法是检测线程是否被中断,如果线程被中断返回true,否则false。重点线程的中断状态不受影响
。
3.3、Thread.interrupted();//线程内部方法,需要在线程内部调用。
线程复位方法,如果线程是中断状态,就改成非中断状态,如果线程是非中断状态,保持非中断现状。
分析jdk源码:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
private native void interrupt0();
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
private native boolean isInterrupted(boolean ClearInterrupted);
5、源码分析:
5.1、isInterrupted()、interrupted()分析
isInterrupted()、interrupted()底层都是用Thread的native方法isInterrupted(boolean ClearInterrupted),区别就是需不需要复位interrupted状态,isInterrupted()不需要复位,interrupted()需要复位。
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
OSThread* osthread = thread->osthread();
bool interrupted = osthread->interrupted();
if (interrupted && clear_interrupted) {
osthread->set_interrupted(false);
// consider thread->_SleepEvent->reset() ... optional optimization
}
return interrupted;
}
源码中clear_interrupted==true时,会执行osthread->set_interrupted(false);
,这也解释了interrupted()复位的原因。
5.2、interrupt()分析
hotspot/src/share/prims/jvm.cpp:3289
,找到 JVM_Interrupt 的定义:
JVM_ENTRY(void, JVM_Interrupt(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_Interrupt");
// Ensure that the C++ Thread and OSThread structures aren't freed before we operate
oop java_thread = JNIHandles::resolve_non_null(jthread);
MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
// We need to re-resolve the java_thread, since a GC might have happened during the
// acquire of the lock
JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
if (thr != NULL) {
Thread::interrupt(thr);
}
JVM_END
hotspot/src/share/vm/runtime/thread.cpp
文件,找到Thread::interrupt
void Thread::interrupt(Thread* thread) {
trace("interrupt", thread);
debug_only(check_for_dangling_thread_pointer(thread);)
os::interrupt(thread);
}
Thread::interrupt 方法调用了 os::interrupt 方法,这个是调 用平台的 interrupt 方法,这个方法的实现是在 os_*.cpp 文件中,其中星号代表的是不同平台,因为 jvm 是跨平台 的,所以对于不同的操作平台,线程的调度方式都是不一 样的。我们以 os_linux.cpp 文件为例:
hotspot/src/hotspot/os/linux/vm/os_linux.cpp:4192
文件,找到os::interrupt(thread)
void os::interrupt(Thread* thread) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
"possibility of dangling Thread pointer");
OSThread* osthread = thread->osthread();
if (!osthread->interrupted()) {
osthread->set_interrupted(true);
// More than one thread can get here with the same value of osthread,
// resulting in multiple notifications. We do, however, want the store
// to interrupted() to be visible to other threads before we execute unpark().
OrderAccess::fence();
ParkEvent * const slp = thread->_SleepEvent ;
if (slp != NULL) slp->unpark() ;
}
// For JSR166. Unpark even if interrupt status already was set
if (thread->is_Java_thread())
((JavaThread*)thread)->parker()->unpark();
ParkEvent * ev = thread->_ParkEvent ;
if (ev != NULL) ev->unpark() ;
}
set_interrupted(true)
实际上就是调用 osThread.hpp 中的 set_interrupted()方法,在 osThread 中定义了一个成员属 性 volatile jint _interrupted;
通过上面的代码分析可以知道,thread.interrupt()方法实际 就是设置一个 interrupted 状态标识为 true、并且通过 ParkEvent 的 unpark 方法来唤醒线程。
- 对于 synchronized 阻塞的线程,被唤醒以后会继续尝试
获取锁,如果失败仍然可能被 park
- 对于 synchronized 阻塞的线程,被唤醒以后会继续尝试
- 在调用 ParkEvent 的 park 方法之前,会先判断线程的中
断状态,如果为 true,会清除当前线程的中断标识
- 在调用 ParkEvent 的 park 方法之前,会先判断线程的中
- Object.wait 、 Thread.sleep 、Thread.join() 会抛出InterruptedException
需要注意的是,InterruptedException 异常的抛出并不意味 着线程必须终止,而是提醒当前线程有中断的操作发生, 至于接下来怎么处理取决于线程本身,比如:
- 直接捕获异常不做任何处理
- 将异常往外抛出
- 停止当前线程,并打印异常信息
hotspot/src/share/vm/runtime/osThread.hpp
文件,
class OSThread: public CHeapObj<mtThread> {
friend class VMStructs;
private:
OSThreadStartFunc _start_proc; // Thread start routine
void* _start_parm; // Thread start routine parameter
volatile ThreadState _state; // Thread state *hint*
volatile jint _interrupted; // Thread.isInterrupted state
public:
......
void set_interrupted(bool z) { _interrupted = z ? 1 : 0; }
拿Thread.sleep()方法,来佐证一下interrupte()功能:
hotspot/src/share/prims/jvm.cpp:
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
JVMWrapper("JVM_Sleep");
if (millis < 0) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
if (Thread::is_interrupted (THREAD, true) && !HAS_PENDING_EXCEPTION) {
THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
}
// Save current thread state and restore it at the end of this block.
// And set new thread state to SLEEPING.
JavaThreadSleepState jtss(thread);
如果线程处于中断Thread::is_interrupted (THREAD, true)
,那么就执行:THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
is_interrupted 是true,然后抛出一个 InterruptedException 异常。到此为止,我们就已经分析清 楚了中断的整个流程。
参考资料:
《深入理解Java虚拟机-2nd》
《Java 并发编程实战》
《Java 并发编程的艺术》