当前位置:网站首页>Locksupport: a very flexible thread tool class

Locksupport: a very flexible thread tool class

2020-12-07 18:58:51 Yugong wants to move mountains

LockSupport Is a programming tool class , It is mainly used to block and wake threads . We can do a lot of things with it , Today is mainly about the explanation of this tool class , I hope it helps you :

One 、LockSupport brief introduction




1、LockSupport What is it?

It was mentioned at the beginning that ,LockSupport Is a thread tool class , All methods are static , The thread can be blocked at any location , You can also wake up anywhere .

There are actually two main types of methods inside it :park( Stop blocking threads ) and unpark( Start the wake-up thread ).

//(1) Block the current thread 
public static void park(Object blocker)
//(2) Pause current thread , There is a timeout
public static void parkNanos(Object blocker, long nanos)
//(3) Pause current thread , Until a certain time
public static void parkUntil(Object blocker, long deadline)
//(4) Suspend the current thread indefinitely
public static void park()
//(5) Pause current thread , However, there is a time-out limit
public static void parkNanos(long nanos)
//(6) Pause current thread , Until a certain time
public static void parkUntil(long deadline);  
//(7) Resume current thread
public static void unpark(Thread thread)
public static Object getBlocker(Thread t);

Notice the top 123 Method , There is one. blocker, This blocker It is used to record who is blocked when a thread is blocked . For thread monitoring and analysis tools to locate causes .

Now we know LockSupport It's used to block and wake up threads , And I believe we all know wait/notify It's also used to block and wake up threads , Compared to it ,LockSupport What are the advantages ?

2、 And wait/notify contrast

Let's assume that you already know wait/notify The mechanism of , If you don't understand , You can search online , It's simple . I believe that since you have learned this LockSupport, I believe you have learned in advance wait/notify.

Let's start with a use case :

public class LockSupportTest {
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(getName() + "  Enter thread ");
            LockSupport.park();
            System.out.println("t1 End of thread run ");
        }
    }
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        System.out.println("t1 Has been launched , But it's done internally park");
        LockSupport.unpark(t1);
        System.out.println("LockSupport the unpark");
    }
}

The above code means , We define a thread , But it's done internally park, Therefore need unpark To wake up and carry on , But up there , We are MyThread On going park, stay main Thread unpark.

Like to see , Like and wait/notify There's no difference . What's the difference between him ? This requires careful observation . There are two main points here :

(1)wait and notify All are Object The method in , The lock object must be obtained before calling these two methods , however park You can lock a thread without getting a lock on an object .

(2)notify Only one thread can be randomly selected to wake up , Unable to wake the specified thread ,unpark Can wake up a specified thread .

The difference is these two , Or mainly from park and unpark To explain the angle of . Since the LockSupport So strong , Let's take a look at his source code .

Two 、 Source code analysis ( be based on jdk1.8)




1、park Method

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false0L);
        setBlocker(t, null);
    }

blocker It is used to record who is blocked when a thread is blocked . For thread monitoring and analysis tools to locate causes .setBlocker(t, blocker) The function of the method is to record t Threads are made by broker Obstructed . So we focus only on the core approach , That is to say UNSAFE.park(false, 0L).

UNSAFE Is a very powerful class , His operation is based on the underlying , That is to say, you can operate memory directly , So we start from JVM From the perspective of :

Every java Every thread has a Parker example :

class Parker : public os::PlatformParker {
private:
  volatile int _counter ;
  ...
public:
  void park(bool isAbsolute, jlong time);
  void unpark();
  ...
}
class PlatformParker : public CHeapObj<mtInternal> {
  protected:
    pthread_mutex_t _mutex [1] ;
    pthread_cond_t  _cond  [1] ;
    ...
}

Let's take a different angle to understand park and unpark, Think about it ,unpark In fact, it is equivalent to a license , Tell specific threads that you can stop , Specific threads want park When you stop, when you see permission , You can immediately stop and continue to run . So the execution order can be reversed .

Now with this concept , Let's experience the above JVM level park Methods , Inside this counter Field , It's used to record what's called “ The license ” Of .

This small summary comes from :https://www.jianshu.com/p/1f16b838ccd8

When calling park when , First try to see if you can get it directly “ The license ”, namely _counter>0 when , If it works , Then put _counter Set to 0, And back to .

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

If it doesn't work , Then construct a ThreadBlockInVM, Then check that the _counter Is it right? >0, If it is , Then put _counter Set to 0,unlock mutex And back to :

  ThreadBlockInVM tbivm(jt);
  // no wait needed
  if (_counter > 0)  { 
    _counter = 0;
    status = pthread_mutex_unlock(_mutex);

otherwise , Then judge the waiting time , Then call pthread_cond_wait Function to wait for , If waiting to return , Then put _counter Set to 0,unlock mutex And back to :

if (time == 0) {  
  status = pthread_cond_wait (_cond, _mutex) ;  
}  
_counter = 0 ;  
status = pthread_mutex_unlock(_mutex) ;  
assert_status(status == 0status"invariant") ;  
OrderAccess::fence();  

This is the whole park The process of , To sum up, it's consumption “ The license ” The process of .

2、unpark

Let's take a look at JDK Source code :

    /**
     * Makes available the permit for the given thread, if it
     * was not already available.  If the thread was blocked on
     * {@code park} then it will unblock.  Otherwise, its next call
     * to {@code park} is guaranteed not to block. This operation
     * is not guaranteed to have any effect at all if the given
     * thread has not been started.
     *
     * @param thread the thread to unpark, or {@code null}, in which case
     *        this operation has no effect
     */

    public static void unpark(Thread thread) {
        if (thread != null)
            UNSAFE.unpark(thread);
    }

The note above means to license thread production .

When unpark when , It's much simpler , Set up directly _counter by 1, Again unlock mutext return . If _counter The previous value was 0, And call pthread_cond_signal Wake up in park Threads waiting in :

void Parker::unpark() {  
  int s, status ;  
  status = pthread_mutex_lock(_mutex);  
  assert (status == 0"invariant") ;  
  s = _counter;  
  _counter = 1;  
  if (s < 1) {  
     if (WorkAroundNPTLTimedWaitHang) {  
        status = pthread_cond_signal (_cond) ;  
        assert (status == 0"invariant") ;  
        status = pthread_mutex_unlock(_mutex);  
        assert (status == 0"invariant") ;  
     } else {  
        status = pthread_mutex_unlock(_mutex);  
        assert (status == 0"invariant") ;  
        status = pthread_cond_signal (_cond) ;  
        assert (status == 0"invariant") ;  
     }  
  } else {  
    pthread_mutex_unlock(_mutex);  
    assert (status == 0"invariant") ;  
  }  
}  

ok, Now we have analyzed the source code , The whole process is actually the process of production license and consumption license . And the production process can be reversed . That is to say, to produce first and then to consume . Let's use a few examples to test a wave of .

3、 ... and 、LockSupport Use



1、 First interrupt Again park

public class LockSupportTest {
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(getName() + "  Enter thread ");
            LockSupport.park();
            System.out.println("  End of run ");
            System.out.println(" Whether to interrupt :" + Thread.currentThread().isInterrupted());
        }
    }
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
        System.out.println("t1 The thread has started , But inside LockSupport the park");
        t1.interrupt();
        System.out.println("main Thread end ");
    }
}

Let's take a look at the results :


2、 First unpark Again park

public static class MyThread extends Thread {
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "  Enter thread ");
            LockSupport.park();
            System.out.println("  End of run ");
        }
    }

We just need to park Sleep before 1 Second , This ensures that unpark Execute first .

OK, Today's article begins with this , If there is a problem , Please criticize and correct .

To whip with a whip , The top will spin . I'm Yugong , To move mountains .



This article is from WeChat official account. - Yugong wants to move mountains (fdd_sxu_nwpu).
If there is any infringement , Please contact the support@oschina.cn Delete .
Participation of this paper “OSC Source creation plan ”, You are welcome to join us , share .

版权声明
本文为[Yugong wants to move mountains]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201207184532613g.html