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 学习笔记