LockSupport类里面的park()和unpark()

LockSupport类里面的park()和unpark()作用是什么

LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,可以通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒。

我们写一个例子来看看这个工具类怎么用的。

下面的代码运行过程是这样的:

首先是main运行,然后启动t1线程,但是呢,因为在t1线程里面调用了LockSupport.park(),所以t1线程就在第10行被阻塞住了,所以不执行第11行
然后执行main执行第15行,第16行,然后main线程执行在第17行,然后就把t1线程给唤醒了,注意t1线程醒了之后会继续往下走,所以此时就会执行第11行代码

package com.mqk.cache;

import lombok.SneakyThrows;

import java.util.concurrent.locks.LockSupport;

public class Hello {
    static ChangeObjectThread t1 = new ChangeObjectThread("t1");

    public static class ChangeObjectThread extends Thread {
        public ChangeObjectThread(String name) {
            super(name);
        }
        @SneakyThrows
        @Override public void run() {
            LockSupport.park();  // 假设是第10行
            System.out.println(getName() +"继续执行");// // 假设是第11行
        }
    }

    public static void main(String[] args) throws InterruptedException {
        t1.start();
        System.out.println("main运行");// 假设是第15行
        Thread.sleep(1000L);// 假设是第16行
        LockSupport.unpark(t1);// 假设是第17行
    }
}


所以最终结果如下所示,在输出main运行之后,会停顿大概1秒,然后继续输出t1继续执行

main运行
t1继续执行

这是我们一般使用LockSupport类正常的用法,推荐使用这种用法(其实就是先LockSupport.park(),然后在LockSupport.unpark())

park和unpark的灵活之处

在Java5里是用wait/notify/notifyAll来同步的。wait/notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。这样就很麻烦了。

但是使用park和unpark了之后,我们可以解决上面的问题。就是一个线程它在启动之后,可以先被别的线程unPark(),然后这个线程在进行park()

什么意思呢,比如下面的代码

首先还是main线程运行,然后执行第11行,然后在第12行启动t1线程
因为第6行睡眠1秒,所以是main线程首先执行第13行,此时t1线程就被main线程先进行unPark()
然后1秒过后,t1线程执行第7行,在这里才被park()掉,但是在这样的情况下,t1线程是没有被阻塞的,原因就是t1线程先被main线程unpark()了,然后t1线程执行第8行。

package com.mqk.cache;

import lombok.SneakyThrows;

import java.util.concurrent.locks.LockSupport;

public class Hello {
    static ChangeObjectThread t1 = new ChangeObjectThread("itqiankun.com");

    public static class ChangeObjectThread extends Thread {
        public ChangeObjectThread(String name) {
            super(name);
        }
        @SneakyThrows
        @Override public void run() {
            Thread.sleep(1000L);// 假设第6行
            LockSupport.park();// 假设第7行
            System.out.println(getName() +"继续执行");// 假设第8行
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main运行"); // 假设第11行
        t1.start();// 假设第12行
        LockSupport.unpark(t1);// 假设第13行
    }
}


所以最终结果如下所示,在输出main运行之后,会停顿大概1秒,然后继续输出itqiankun.com继续执行

main运行
itqiankun.com继续执行

但是这样使用的时候要注意一个问题,就是LockSupport类里面的park()和unpark()多次调用

package com.mqk.cache;

import lombok.SneakyThrows;

import java.util.concurrent.locks.LockSupport;

public class Hello {
    static ChangeObjectThread t1 = new ChangeObjectThread("itqiankun.com");

    public static class ChangeObjectThread extends Thread {
        public ChangeObjectThread(String name) {
            super(name);
        }
        @SneakyThrows
        @Override public void run() {
            Thread.sleep(1000L);
            for(int i=0;i<2;i++){
                LockSupport.park();
            }
            System.out.println(getName() +"继续执行");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("main运行");
        t1.start();
        for(int i=0;i<2;i++){
            LockSupport.unpark(t1);
        }
    }
}

当执行上面的代码的时候,可以看到线程被阻塞导致程序一直无法结束掉。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxW6vhHx-1625016883996)(https://itqiankun.oss-cn-beijing.aliyuncs.com/picture/blogArticles_new/2021/02/20/1613825247.png ‘点击图片可以看的更清楚哦’)]

为什么会出现上面的问题呢,这里需要了解LockSupport类的底层实现,

class Parker : public os::PlatformParker {
private:
  volatile int _counter ;
  ...
public:
  void park(bool isAbsolute, jlong time);
  void unpark();
  ...
}
class PlatformParker : public CHeapObj<mtInternal> {
  protected:
    pthread_mutex_t _mutex [1] ;
    pthread_cond_t  _cond  [1] ;
    ...
}

LockSupport就是通过控制变量_counter来对线程阻塞唤醒进行控制的。原理有点类似于信号量机制。

当调用park()方法时,会将_counter置为0,同时判断前值,等于1说明前面被unpark过,则直接退出,否则将使该线程阻塞。

当调用unpark()方法时,会将_counter置为1,同时判断前值,等于0会进行线程唤醒,否则直接退出。

当先调用两次unpark()之后,那么_counter置还是1,然后第一次调用park(),将_counter置为0,同时前值等于1,所以直接退出了,但是在第二次park()的时候,_count值是0,所以此时直接被阻塞了。

所以使用LockSupport类里面的park()和unpark()的时候,推荐使用先LockSupport.park(),然后在LockSupport.unpark()

能看到这里的同学,就帮忙右上角点个赞吧,Thanks♪(・ω・)ノ

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: LockSupport是Java并发包中的一个核心基础,它提供了线程阻塞和唤醒的功能。在AQS框架中,它主要被用来实现线程的阻塞和唤醒,而Unsafe则提供了CAS操作,用于实现AQS的同步机制。因此,LockSupport和Unsafe这两个都是AQS框架不可或缺的组成部分,两者配合使用,使得AQS能够高效地实现线程同步。 ### 回答2: LockSupport是Java并发编程中的一个核心基础,主要提供了线程阻塞和唤醒的功能。 在AQS框架中,LockSupport被广泛应用于线程的阻塞与唤醒操作,是实现锁和同步器的重要组成部分。 首先,LockSupport提供了park()和unpark()两个方法,这两个方法可以实现线程的阻塞和唤醒操作。线程调用park()方法后会进入阻塞状态,直到其他线程调用unpark()方法唤醒该线程;而线程调用unpark()方法后,如果该线程已经被阻塞,会立即解除阻塞状态。通过这两个方法的灵活组合,能够很方便地实现线程的阻塞与唤醒。 其次,LockSupport内部使用了似于信号量的机制,每个线程都会关联一个许可证。调用一次park()方法会消耗一个许可证,而调用一次unpark()方法会增加一个许可证。如果线程在调用park()方法前已经有了许可证,那么调用park()方法后不会阻塞,而是直接消耗掉这个许可证。这种在许可证上的管理,使得LockSupport能够实现更加灵活的线程阻塞和唤醒。 最后,LockSupport使用了底层的操作系统机制来实现线程的阻塞和唤醒,效率较高。相比于传统的等待-通知机制(wait-notify),LockSupport的实现更加简洁高效,并且不需要先获得对象的监视器,而是通过许可证的方式进行线程的阻塞和唤醒。 综上所述,LockSupport作为AQS框架的重要组成部分,提供了灵活、高效的线程阻塞和唤醒机制,是Java并发编程中不可或缺的核心基础之一。 ### 回答3: LockSupport是Java并发编程中的核心基础之一,它提供了线程阻塞和唤醒的功能,可以在任意线程中进行阻塞和唤醒操作。 首先,LockSupport提供的park/unpark操作相比其他线程同步器,如synchronized关键字或者wait/notify机制,具有更高的灵活性和性能。它不依赖于任何特定的对象,而是直接与线程进行交互。这使得LockSupport可以用于更广泛的场景,例如线程间的通信、同步控制和中断处理等。 其次,LockSupport是AQS(AbstractQueuedSynchronizer)框架的关键组件之一。AQS框架提供了一种可重入的、高效的同步器实现方式,被广泛应用于Java并发编程中。而LockSupport作为AQS框架的辅助,为其提供了底层的线程阻塞和唤醒的能力。 在AQS框架中,LockSupportpark/unpark方法被用于实现线程的阻塞和唤醒操作,实现了线程间的同步与互斥。它通过使用不可重入的同步状态来管理线程的阻塞和唤醒,避免了传统同步机制中存在的死锁和饥饿问题。 此外,LockSupportpark/unpark方法还可以与其他并发库结合使用,如Future、CountDownLatch和Semaphore等。通过LockSupport,我们可以实现更加灵活和高效的并发编程,提高系统的吞吐量和性能。 综上所述,LockSupport作为AQS框架的关键组件之一,不仅提供了线程阻塞和唤醒的功能,还具有较高的灵活性和性能。因此,LockSupport也被认为是Java并发编程中的核心基础
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值