并发基础-(1)-线程状态(BLOCKED、TIMED_WAITING、WAITING等)、线程启动方式、线程关闭方式(interrupt、isInterrupted、interrupted))

死神---一护

目录:

  • 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 方法来唤醒线程。

    1. 对于 synchronized 阻塞的线程,被唤醒以后会继续尝试
      获取锁,如果失败仍然可能被 park
    1. 在调用 ParkEvent 的 park 方法之前,会先判断线程的中
      断状态,如果为 true,会清除当前线程的中断标识
    1. Object.wait 、 Thread.sleep 、Thread.join() 会抛出InterruptedException

需要注意的是,InterruptedException 异常的抛出并不意味 着线程必须终止,而是提醒当前线程有中断的操作发生, 至于接下来怎么处理取决于线程本身,比如:

    1. 直接捕获异常不做任何处理
    1. 将异常往外抛出
    1. 停止当前线程,并打印异常信息

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 并发编程的艺术》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容