JAVA并发梳理(一)LockSupport

LockSupport是线程的阻塞原语,用来阻塞和唤醒线程。理解了这个之后,对理解高级的并发工具/组建都很有帮助。

其基本API包括:
park()
unpark()
内部都是通过调用Unsafe来完成。

    public static void park() {
        UNSAFE.park(false, 0L);
    }

park()提供带参数版本,可以加上时间参数,表示阻塞的时间;或者deadline,表示阻塞到什么时间为止。也可以park(Object blocker),入参增加一个Object 对象,用来记录导致线程阻塞的阻塞对象,方便进行问题排查。

一个简单的例子:

public class LockSupportTest {
    public static void main(String[] args) {
        final Object obj = new Object();
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                LockSupport.park();
                //LockSupport.park(obj);
            }
        });
        t.start();
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
        }
        LockSupport.unpark(t);
    }
}

通过jstack查看线程状态。park()之后线程进入waiting状态。

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001b43d800 nid=0x295c waiting on condition [0x000000001bfef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
        at com.company.multithread.LockSupportTest$1.run(LockSupportTest.java:14)
        at java.lang.Thread.run(Thread.java:745)

调用park(blocker)的时候,可以看到parking to wait for <0x0000000780f1c3b0>.

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001b083800 nid=0x2070 waiting on condition [0x000000001bbef000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000780f1c3b0> (a java.lang.Object)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at com.company.multithread.LockSupportTest$1.run(LockSupportTest.java:14)
        at java.lang.Thread.run(Thread.java:745)

各种并发工具或者组建内部都是通过调用LockSupport.park()unpark()来实现线程阻塞和唤醒的。所谓原语。比如,可以看ReentrantLock的内部,lock()实现

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

这里的this就是lock实例,线程由于没有抢到lock实例的锁,所以被它阻塞。

synchronzed vs. LockSupport.park()
  • synchronzed 致使线程阻塞,线程会进入到 BLOCKED 状态,而调用 LockSupprt.park() 方法阻塞线程会致使线程进入到 WAITING 状态
  • synchronzed 阻塞的线程加入到同步队列,再次被唤醒的线程是随机从同步队列中选择的,而LockSupport.unpark(thread) 可以指定线程对象唤醒指定的线程
    public static void main(String[] args) {
        final Object obj = new Object();
        final Thread syncThread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        Thread.sleep(1000000);
                    } catch (InterruptedException e) {
                    }
                }
            }
        });
        syncThread.start();

        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println("Finally get the obj synchronizer.");
                }
            }
        });
        t.start();
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
        }
    }

通过jstack查看线程状态如下。

"Thread-1" #12 prio=5 os_prio=0 tid=0x000000001ae35000 nid=0x528 waiting for monitor entry [0x000000001babf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.company.multithread.LockSupportTest$2.run(LockSupportTest.java:29)
        - waiting to lock <0x0000000780f1c370> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
        - None

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001ae32000 nid=0x1c8c waiting on condition [0x000000001b9bf000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at com.company.multithread.LockSupportTest$1.run(LockSupportTest.java:17)
        - locked <0x0000000780f1c370> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)
注意park不会释放原本持有的锁
public class LockSupportTest {
    public static void main(String[] args) throws InterruptedException {
        Object obj1 = new Object();
        new Thread(new LS(obj1)).start();
        Thread.sleep(1000);
        new Thread(new LS(obj1)).start();
        Thread.sleep(10000000);
    }

    static class LS implements Runnable {
        Object obj;

        LS(Object obj) {
            this.obj = obj;
        }

        @Override
        public void run() {
            synchronized (obj) {
                System.out.println("Getting lock for obj1 ");
                LockSupport.park();
            }
        }
    }
}

通过jstack来查看线程状态如下:

"Thread-1" #12 prio=5 os_prio=0 tid=0x000000001f05f000 nid=0x2614 waiting for monitor entry [0x000000002029f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at multithread.LockSupportTest$LS.run(LockSupportTest.java:26)
        - waiting to lock <0x000000076dade490> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
        - None

"Thread-0" #11 prio=5 os_prio=0 tid=0x000000001f059000 nid=0x4084 waiting on condition [0x000000001e75f000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304)
        at multithread.LockSupportTest$LS.run(LockSupportTest.java:27)
        - locked <0x000000076dade490> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:745)

引用
Java LockSupport 学习笔记

你可能感兴趣的:(JAVA并发梳理(一)LockSupport)