Java 响应式的锁

发布于 2025-01-14 11:04:25 字数 3620 浏览 4 评论 0

由于响应式技术栈基本都是基于 eventloop 的,而对于当前(2022 年 5 月 18 日)java 的并发模型都是基于内核线程进行建模的,多个请求并发跑在同一个线程上导致了 synchronized 和 J.U.C 包的锁不再适用

而并发中锁又是必须的,那么我们该怎么办?

kotlin 协程锁

以当前 eventloop 作为调度器驱动多个无栈协程,为每一个请求分配一个协程即可

本质上这种并不会阻塞住当前的内核线程,而是”阻塞“当前协程,实际上就是当前协程通过 cas 抢到锁之后来处理自己的业务,此时其他抢不到的阻塞等待调度,锁持有者协程放锁时恢复等待的协程执行

1652868444511

实际原理很简单:cas 看看能不能拿到 不能拿到把当前的 continuation 封装到 waiter 里面 等待 resume

1652869305307

而 unlock 方法则是取出第一个等待的 waiter 节点,然后恢复其中的 continuation 执行就行了

1652869446926

vertx 的异步锁

1652868681246

实际上就是通过 ConcurrentMap#compute 的原子特性直接加入等待队列

1652868933781

1652869115287

若发现当前队列没有竞争者则直接获取到锁,触发 future 回调

而释放锁的 release 则是这样的

  @Override
  public void release() {
    if (invoked.compareAndSet(false, true)) {
    nextWaiter(lockName);
    }
  }
private void nextWaiter(String lockName) {
  List<LockWaiter> waiters = waitersMap.compute(lockName, (s, list) -> {
    return list == null || list.size() == 1 ? null : new ArrayList<>(list.subList(1, list.size()));
  });
  if (waiters != null) {
    waiters.get(0).acquireLock();
  }
  }

直接让下一个等待者获取到锁即可

java 的 loom

如果我还是想用 juc 这种 lock 怎么办?

那么我们就可以使用 project loom(jdk19 将 preview),将当前的 eventloop 或者其他的线程池作为有栈协程的调度器,由于 loom 带来的 virtualthread(协程)是 Thread 的子类,且 LockSupport 类也对其有适配,阻塞虚拟线程而不是内核线程

val router = Router.router(vertx)
val lock = ReentrantLock()
  router.get()
  .handler{
    Thread.startVirtualThread {
    lock.lock()
    try {
      //做你要的处理
    }finally {
      lock.unlock()
    }
    }
  }

然后我们来看看 LockSupport#park 方法 相当于从当前的内核线程上卸载这个协程 然后换一个协程来执行

 public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    try {
      if (t.isVirtual()) {
        VirtualThreads.park();
      } else {
        U.park(false, 0L);
      }
    } finally {
      setBlocker(t, null);
    }
  }
private void doPark() {
    // complete immediately if parking permit available or interrupted
    if (getAndSetParkPermit(false) || interrupted)
      return;

    // park the thread
    setState(PARKING);
    try {
      if (!yieldContinuation()) {
        // park on the carrier thread when pinned
        parkOnCarrierThread(false, 0);
      }
    } finally {
      assert (Thread.currentThread() == this) && (state() == RUNNING);
    }
  }
private boolean yieldContinuation() {
    boolean notifyJvmti = notifyJvmtiEvents;

    // unmount
    if (notifyJvmti) notifyJvmtiUnmountBegin(false);
    unmount();
    try {
      return Continuation.yield(VTHREAD_SCOPE);
    } finally {
      // re-mount
      mount();
      if (notifyJvmti) notifyJvmtiMountEnd(false);
    }
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

扛刀软妹

暂无简介

文章
评论
26 人气
更多

推荐作者

hncloud

文章 0 评论 0

13545243122

文章 0 评论 0

探春

文章 0 评论 0

樱桃奶球

文章 0 评论 0

LR

文章 0 评论 0

J.smile

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文