interrupt () interrupts impact on LockSupport.park () behavior

Original Excerpt: https://www.jianshu.com/p/d48f854ead85

1. interrupt LockSupport.park () returns directly

public class MultInterruptParkDemo {
    public static volatile boolean flag = true;
    public static void main(String[] args) {
        ThreadDemo04 t4 = new ThreadDemo04();
        t4.start();
        t4.interrupt();
        flag = false;
    }
    public static class ThreadDemo04 extends Thread {
        @Override
        public void run() {
            while (flag) {
            }
            LockSupport.park();
            System.out.println ( "appears in the first printing of the present Park () after");
            LockSupport.park();
            System.out.println ( "print appears in the present second Park () after");
        }
    }
}

result:

After this first appeared in print park ()
After this printing appears in the second Park ()

1.1 Analysis

Thread interrupt method analysis (including HotSpot source) in the interrupt source:

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);

If the thread is not set interrupt flag will be set.

LockSupport and HotSpot layer Parker :: park / unpark analysis in the park Source:

void Parker::park(bool isAbsolute, jlong time) {
  // Ideally we'd do something useful while spinning, such
  // as calling unpackTime().

  // Optional fast-path check:
  // Return immediately if a permit is available.
  // We depend on Atomic::xchg() having full barrier semantics
  // since we are doing a lock-free update to _counter.
  if (Atomic::xchg(0, &_counter) > 0) return;

  Thread* thread = Thread::current();
  assert(thread->is_Java_thread(), "Must be JavaThread");
  JavaThread * jt = (JavaThread *) thread;

  // Optional optimization -- avoid state transitions if there's an interrupt pending.
  // Check interrupt before trying to wait
  if (Thread::is_interrupted(thread, false)) {
    return;
  }

As long as the thread interrupt flag is set, return directly, and here Thread :: is_interrupted (thread, false) because it is false, it will not clear the interrupt flag.

1.2 summary

  • t4.interrupt () sets the thread's interrupt flag
  • LockSupport.park () checks whether a thread interrupt flag, if set, is returned (this does not clear the interrupt flag)

2.unpark not accumulate license (up to 1)

public class MultInterruptParkDemo2 {
    public static volatile boolean flag = true;
    public static void main(String[] args) {
        ThreadDemo04 t4 = new ThreadDemo04();
        t4.start();
        LockSupport.unpark(t4);
        LockSupport.unpark(t4);
        LockSupport.unpark(t4);
        flag = false;
    }
    public static class ThreadDemo04 extends Thread {
        @Override
        public void run() {
            while (flag) {
            }
            LockSupport.park();
            System.out.println ( "appears in the first printing of the present Park () after");
            LockSupport.park();
            System.out.println ( "print appears in the present second Park () after");
        }
    }
}

result:

After this first appeared in print park ()

2.1 Analysis

LockSupport and HotSpot layer Parker :: park / unpark analysis in the park Source:

void Parker::park(bool isAbsolute, jlong time) {
  // Ideally we'd do something useful while spinning, such
  // as calling unpackTime().

  // Optional fast-path check:
  // Return immediately if a permit is available.
  // We depend on Atomic::xchg() having full barrier semantics
  // since we are doing a lock-free update to _counter.
  if (Atomic::xchg(0, &_counter) > 0) return;

Each call will be _counter park directly set to zero.

void Parker::unpark() {
  int s, status ;
  status = pthread_mutex_lock(_mutex);
  assert (status == 0, "invariant") ;
  s = _counter;
  _counter = 1;
Each call will unpark the _counter directly set to 1.

2.2 summary

  • Therefore, the total number of licenses is always kept at 1, no matter how many times unpark calls only will _counter set to 1.
  • _Counter each park will be set to 0, if the prior is 1, the process directly returns. park behind the call will be blocked.

3.Thread.interrupted () clears the interrupt flag

public class MultInterruptParkDemo3 {
    public static volatile boolean flag = true;
    public static void main(String[] args) {
        ThreadDemo04 t4 = new ThreadDemo04();
        t4.start();
        t4.interrupt();
        flag = false;
    }
    public static class ThreadDemo04 extends Thread {
        @Override
        public void run() {
            while (flag) {
            }
            LockSupport.park();
            System.out.println ( "appears in the first printing of the present Park () after");
            System.out.println(Thread.interrupted());
            System.out.println(Thread.interrupted());
            LockSupport.park();
            System.out.println ( "print appears in the present second Park () after");
        }
    }
}

result:

After this first appeared in print park ()
true
false

3.1 Analysis

Thread interrupt method analysis (including HotSpot source) in Thread.interrupted () Source:

public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
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;
}

If you can see the break and clear_interrupted is true, it will clear the interrupt flag.

3.2 summary

Thread.interrupted () Clear the interrupt flag, the second LockSupport.park () does not return directly, but normally blocked.

4.sleep clear the interrupt flag but does not change _counter

public class MultInterruptParkDemo4 {
    public static volatile boolean flag = true;
    public static void main(String[] args) {
        ThreadDemo04 t4 = new ThreadDemo04();
        t4.start();
        t4.interrupt();
        flag = false;
    }
    public static class ThreadDemo04 extends Thread {
        @Override
        public void run() {
            while (flag) {
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace ();
            }
            System.out.println ( "Print this appears) after the first sleep (");
            System.out.println(Thread.interrupted());
            System.out.println(Thread.interrupted());
            LockSupport.park();
            System.out.println ( "print appears in the present second Park () after");
        }
    }
}

result

java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at wz.interrupt.MultInterruptParkDemo4$ThreadDemo04.run(MultInterruptParkDemo4.java:19)
This first appeared in print sleep () after
false
false
After this printing appears in the second Park ()

4.1 Analysis

Thread interrupt method analysis (including HotSpot source) in the interrupt source:

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() ;

}

Calls Parker :: unpark (), then _counter is set to 1.

Reference correlation analysis method of blocking threads (HotSpot layer including source) concerning sleep Source:

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");
  }

If the thread is interrupted, clear interrupt flag and interrupt exception thrown directly back, but did not change _counter.

4.2 summary

  • interrupt calls ((JavaThread *) thread) -> parker () -> unpark (), the _counter set to 1, that is, after the call to park without blocking
  • If sleep interruption is detected directly clear the interrupt flag, and throws an exception.
  • So two Thread.interrupted () returns false, and the LockSupport.park () does not block.

5. For LockSupport.park () blocked summary

The following two conditions are either established, park () will not be blocked:

  • Interrupt flag is present ( the wait, the Join, SLEEP or Thread.interrupted () will clear the interrupt flag)
  • _counter 1 (before calling the unpark or interrupt)

reference


Author: Wang reconnaissance
link: https: //www.jianshu.com/p/d48f854ead85
Source: Jane books
are copyrighted by the author. Commercial reprint please contact the author authorized, non-commercial reprint please indicate the source.

Guess you like

Origin www.cnblogs.com/septemberFrost/p/12200755.html