AQS Semaphore共享锁源码分析原理解读

用途

设置一定数量的资源,只有获取到资源的线程才会执行下去,否则会一直等待,和ReentrantLock不同的是,ReentrantLock只允许一个线程获取资源,而Semaphore允许多个线程获取到资源

DEMO

package com.skindow.sql;

import java.util.concurrent.Semaphore;

/**
 * @ Author     :syc.
 * @ Date       :Created in 16:03 2021/3/12
 * @ Description:
 * @ Modified By:
 * @ Version:
 */
public class SemaphoreTest {

    public static final int COUNT = 1;

    public static final Semaphore SEMAPHORE = new Semaphore(COUNT);

    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            SemaphoreTest.myThread myThread = new SemaphoreTest.myThread(i);
            myThread.setName("test_" + i);
            myThread.start();
        }
    }

    private static class myThread extends Thread {
        public Integer i;

        public myThread(Integer i) {
            this.i = i;
        }

        @Override
        public void run() {
            try {
                boolean flag = false;
                int j = 0;
                System.out.println(Thread.currentThread().getName() + " 获取共享锁中...");
                SEMAPHORE.acquire();
                System.out.println(Thread.currentThread().getName() + " 已获得共享锁,还剩" + SEMAPHORE.availablePermits() + "个共享锁");
                for (; ; ) {
                    if (getCount() > 0 && flag) {
                        System.out.println(Thread.currentThread().getName() + " 获取共享锁中...");
                        SEMAPHORE.acquire();
                        System.out.println(Thread.currentThread().getName() + " 已获得共享锁,还剩" + SEMAPHORE.availablePermits() + "个共享锁");
                    }
                    flag = true;
                    j++;
                    System.out.println(Thread.currentThread().getName() + " RUNNING");
                    Thread.sleep(5000);
                    if (j == 2) {
                        SEMAPHORE.release();
                        System.out.println(Thread.currentThread().getName() + " 释放当前共享锁...");
                        Thread.sleep(1000);
                        continue;
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static synchronized int getCount() {
        return SEMAPHORE.availablePermits();
    }
}

结构图

在这里插入图片描述

构造方法

	//初始化一个非公平同步阻塞队列,permits为共享锁数量
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }
    //根据fair来判断是初始化公平锁还是非公平锁同步阻塞队列
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

acquire() 方法说明

以下Semaphore acquire() 和CountDownLatch await() 方法类似,可看上期解读
CountDownLatch源码分析,不同点在于判断共享资源逻辑上,在CountDownLatch中,如果还有共享资源,则将当前线程挂起,并加入同步阻塞队列中等待唤醒,而Semaphore则相反,如果没有共享资源可用,则挂起当前线程,等其他线程将共享资源释放在将其唤醒。从这里不同点就可以看出两个共享资源锁的区别了

这里简单说下acquire流程

有中断就抛出中断异常,判断当前信号量是否大于0,也就是可共享资源尚有余否,大于0时,则分配一个共享资源(减一)给当前线程,否则就将当前线程挂起,等待其他线程释放共享资源唤醒其争夺余下的共享资源

Semaphore acquire() 方法
   public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
AbstractQueuedSynchronizer acquireSharedInterruptibly(int arg) 方法
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

AbstractQueuedSynchronizer doAcquireSharedInterruptibly(int arg)
   private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
Semaphore release()方法
    public void release() {
        sync.releaseShared(1);
    }
AbstractQueuedSynchronizer releaseShared(int arg) 方法
    public final boolean releaseShared(int arg) {
    	//释放当前资源
        if (tryReleaseShared(arg)) {
        	//如果资源成功,唤醒队列节点线程
            doReleaseShared();
            return true;
        }
        return false;
    }
release方法总结
  1. 释放当前共享资源
  2. 释放成功,则唤醒同步阻塞队列中满足条件的线程(doReleaseShared 在上期CountDownLatch就介绍过了,这里就不过多解释了)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值