一、例子
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestParkAndUnpark {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park");
LockSupport.park();
System.out.println("child thread end park");
System.out.println("今天又学了一个快捷键,sysout + alt +/ 是控制台" +
"输出的一个快捷键");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("main thread begin unpark");
LockSupport.unpark(thread);
}
}
- 首先建立了一个子线程,然后调用park方法,由于默认情况下,子线程没有持有许可证,因此它会把自己挂起;在主线程中执行了unpark方法,参数为子线程,这样做的目的就是让子线程能够持有许可证,然后子线程调用的park方法就会返回
- 注意点:park方法不会告诉我们是因为哪种原因返回的,因此调用者需要根据之前调用park方法的原因,再次检查条件是否满足,如果不满足的话,还需再次调用park方法
- 例如:根据调用前后的中断状态的对比可以判断是不是因为被中断才返回的。
- 下面为了说明调用park方法后的线程是因为被中断才返回的,我们修改代码
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestParkAndUnpark {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child thread begin park");
while(!Thread.currentThread().isInterrupted()) {
LockSupport.park();
}
System.out.println("child thread end park");
System.out.println("今天又学了一个快捷键,sysout + alt +/ 是控制台" +
"输出的一个快捷键");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("main thread begin unpark");
thread.interrupt();
}
}
- 我们可以从中看出,如果只有中断了子线程,子线程才会运行结束,如果子线程不中断的话,即使调用了LockSupport(thread)方法,也不会中断。
二、void parkNanos(long nanos)方法
- 与park方法相类似,如果该线程没有拿到许可证,那么调用parkNanos(long nanos)方法该线程会立即停止阻塞,并返回;如果有许可证,那么nanos毫秒之后,该线程才会返回。
package com.ruigege.LockSourceAnalysis6;
import java.util.concurrent.locks.LockSupport;
public class TestPark {
public void testPark() {
LockSupport.park();
}
public static void main(String[] args) {
System.out.println("开始park方法");
TestPark testPark = new TestPark();
testPark.testPark();
}
}
- 下面是我们使用parkNanos方法来代替LockSupport.park()方法
LockSupport.park(this);
- 使用这个带参数的park(Object blocker)方法,当线程在没有持有许可证的时候,调用park方法,会被阻塞起来,这个blocker对象会被记录到该线程的内部。
- 使用jstack pid命令可以对线程堆栈进行查看,该线程内部是含有的什么对象
三、park(Object blocker)源码解析
public static void park2(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t,blocker);
UNSAFE.park(false,0L);
setBlocker(t,null);
}
四、void parkNanos(Object blocker,long nanos)方法
五、void parkUtil(Object blocker,long deadline)方法
- 这个方法和parkNanos不同的就是超时时间的算法,parkNanos的超时时间是从线程阻塞开始算起的,而parkUtil方法的超时时间是从1970年开始算起,到某一个时间点的毫秒数
public static void parkUtile(Object blocker,long deadline) {
Thread t = Thread.currentThread();
setBlocker(t,blocker);
UNSAFE.park(false,deadline);
setBlocker(t,null);
}
六、下面再看一个例子
package com.ruigege.LockSourceAnalysis6;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
public class FIFOMutex {
private final AtomicBoolean locked = new AtomicBoolean(false);
private final Queue waiters = new ConcurrentLinkedQueue();
public void lock() {
boolean wasInterrupted = false;
Thread current = Thread.currentThread();
waiters.add(current);
while(waiters.peek() != current || !locked.compareAndSet(false,true)) {
LockeSupport.park(this);
if(Thread.interrupted()) {
wasInterrupted = true;
}
}
waiters.remove();
if(wasInterrupted) {
current.interrupt();
}
}
public void unlock() {
locked.set(false);
LockSupport.unpark(waiters.peek());
}
}
- 这是一个先进先出的锁,也就是只有队列的首元素可以获取锁,在代码(1)如果当前线程不是队首或者当前锁已经被其他线程获取,那么调用park方法挂起自己。
- 然后再代码(2)处做判断,如果park方法是因为被中断而返回的,则忽略中断,并且重置中断标志,复习该方法去
- 在代码(3)中,判断标记,如果标记为true那么中断该线程
- 总结:其实就是其他线程中断了该线程,虽然我对中断信号不感兴趣,忽略它(也就是代码(2)),但是不代表其他线程对该标志不感兴趣,我们还需要恢复一下。
七、源码:
- 所在包:com.ruigege.ConcurrentListSouceCodeAnalysis5
https://github.com/ruigege66/ConcurrentJava
- CSDN:https://blog.csdn.net/weixin_44630050
- 博客园:https://www.cnblogs.com/ruigege0000/
- 欢迎关注微信公众号:傅里叶变换,个人账号,仅用于技术交流