0%

java | park && unpark

他们是 LockSupport 类的方法。

  • park
    • 暂停当前线程
  • ubpark
    • 恢复当前线程

使用

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.redisc;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.LockSupport;

@Slf4j(topic = "c.Run")
public class Run {


public static void main(String[] args) throws Exception {
Thread t1 = new Thread(() -> {
log.debug("start...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("park...");
LockSupport.park();
log.debug("resume");
});
t1.start();

Thread.sleep(2000);
log.debug("unpark");
LockSupport.unpark(t1);
}

}

输出

1
2
3
4
18:53:28.860 [Thread-0] DEBUG c.Run - start...
18:53:29.867 [Thread-0] DEBUG c.Run - park...
18:53:30.859 [main] DEBUG c.Run - unpark
18:53:30.859 [Thread-0] DEBUG c.Run - resume

unpark 既可以在 park 之前调用,也可以之后调用,上面的代码是之后调用,下面的代码是之前调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.redisc;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.LockSupport;

@Slf4j(topic = "c.Run")
public class Run {


public static void main(String[] args) throws Exception {
Thread t1 = new Thread(() -> {
log.debug("start...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("park...");
LockSupport.park();
log.debug("resume");
});
t1.start();

Thread.sleep(1000);
log.debug("unpark");
LockSupport.unpark(t1);
}

}

输出

1
2
3
4
21:13:35.544 [Thread-0] DEBUG c.Run - start...
21:13:36.534 [main] DEBUG c.Run - unpark
21:13:37.550 [Thread-0] DEBUG c.Run - park...
21:13:37.551 [Thread-0] DEBUG c.Run - resume
  • waitnotifynotifyAll 必须配合 Object Monitor 一起使用,而 unpark 不必
  • park & unpark 是以线程为单位进行「阻塞」和「唤醒」的,而 notify 只能随机唤醒一个等待线程
  • park & unpark 可以先 unpark,而 wati & notify 不能先 notify

原理

每个线程都有自己的一个 Parker 对象,由三个部分组成

  • _counter
  • _cond
  • _mutex

举一个例子

  • 线程就像一个旅人,Parker 就像他随身携带的背包,条件变量就好像是背包中的帐篷。_counter 就好像背包中的备用干粮「0 为耗尽、1 为充足」
  • 调用 park 就是看需不需要停下来休息
    • 如果备用干粮耗尽,那么钻进帐篷休息
    • 如果备用条件充足,那么,不需要停留,继续前进
  • 调用 unpark,就是补充干粮,让干粮充足
    • 如果这时线程在帐篷中,就唤醒让他继续前进
    • 如果这时线程还在运行,那么,下次他调用 park 时,仅是消耗备用干粮,不需要停留继续前进
      • 因为背包空间有限,多次 unpark 也只会补充一份干粮
请我喝杯咖啡吧~