public class LockSupportDemo {
public static Object u = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread{
public ChangeObjectThread(String name){
super.setName(name);
}
@Override
public void run(){
synchronized (u){
System.out.println("in "+getName());
LockSupport.park();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1);
LockSupport.unpark(t2);
t1.join();
t2.join();
}
}
这里只是将原来的suspend()方法和resume()方法用
park()方法和unpark()方法做了替换。当然,我们依然
无法保证unpark()方法发生在park()方法之后。
但是执行这段代码,你会发现,它自始至终都可以正常地结束。
不会因为park()方法而导致线程永久挂起。
这是因为LockSupport类使用类似信号量的机制。它为每一个线程准备了一个许可,
如果许可可用,那么park()方法会立即返回,并且消费这个许可(也就是将许可变不可用),
如果许可不可用,就会阻塞,而unpark()方法则使得一个许可变为可用(但是和信号量不同的是,许可不能累加
,你不可能拥有超过一个许可,它永远只有一个)。
这个特点使得,即使unpark()方法操作发生在park()方法之前,
它也可用使下一次的park()方法操作立即返回。也就是上述代码可顺利结束的主要原因。
调用 unpark 给线程一个通行证: 当线程调用了 unpark,它获得了一个许可(通行证)。这个许可有两个作用:
如果线程在调用 park 之前,那么调用 park 时会立即返回,不会阻塞。
如果线程还没有调用 park,那么这个许可就留着,等待线程下一次调用 park 时使用。
两种情况下的作用:
情况一:线程调用了 park: 如果线程在调用 park 之前已经被赋予了许可,那么 park 会立即返回,不会阻塞。
情况二:线程没有调用 park: 如果线程还没有调用 park,但是已经调用了 unpark,那么这个许可就会等待线程下一次调用 park 时使用。当线程下一次调用 park 时,它会消耗这个许可,使得 park 立即返回,不会阻塞。
这种机制的关键点在于,即使 unpark 发生在 park 之前,许可的存在确保了线程在调用 park 时能够顺利通过,不会阻塞。
这使得线程控制更加灵活和可靠。