信号量Semaphore了解过吗?

难堪的一次面试: 信号量Semaphore了解过吗?没有😖

线程同步器CycliBarrier你都不会吗,打击到了我。。

源码详解CountDownLatch

CycliBarrier、CountDownLatch都是减计数器,而Semaphore都是加计数器

下面我们从源码角度来探究Semaphore的内心世界

简单的一个例子

实现一个简单的线程同步例子,semaphore.release(),计数器加一,semaphore.acquire(2),尝试计数器减二,失败,阻塞,成功,直接返回

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class Main{
    public static Semaphore semaphore = new Semaphore(0);
    public static void main(String args[])throws Exception{
        ExecutorService pool = Executors.newFixedThreadPool(2);
        pool.submit(new Runnable(){
            @Override
            public void run() {
                try{
                    System.out.println("Thread1 step1 start");
                    //doSomething
                    semaphore.release();

                    System.out.println("Thread1 step1 end");

                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        });
        pool.submit(new Runnable(){
            @Override
            public void run() {
                try{
                    System.out.println("Thread2 step1 start");
                    //doSomething
                    semaphore.release();
                    System.out.println("Thread2 step1 end");
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        });
        semaphore.acquire(2);
        pool.shutdown();
    }
}

Semaphore类图

semaphore实现依赖AQS,可以参考抽象队列式同步器AQS详解

初始化

支持公平和非公平两种方式, permits是用来初始化state变量

public Semaphore(int permits) {
        sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
 }

release方法

release方法调用sync的releaseShared

public void release() {
        sync.releaseShared(1);
}

releaShared方法

release方法调用tryReleaseShared,释放资源,成功,则尝试唤醒等待的进程。

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            
            doReleaseShared();
            return true;
        }
        return false;
    }

tryReleaseShared方法

protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

acquire方法

acquire方法调用acquireSharedInterruptibly方法,acquireSharedInterruptibly调用doAcquireSharedInterruptibly方法

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

acquireSharedInterruptibly方法

调用tryAcquireShared尝试获取资源,tryAcquireShared调用NofairSync重写的nonfairTryAcquireShared

或者FairSync重写的fairTryAcquireShared.尝试获取资源,失败则进行阻塞队列,进行阻塞等待。

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);
        }
    }
protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
 }
 final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
}

总结

总结一下工作过程

  • 线程A调用Semaphore的acquire(N)方法,尝试获取N个资源,失败,则进入阻塞队列等待
  • 其他线程调用Semaphore的release()方法,释放一个资源
  • 当有N个资源,满足线程A的要求时,线程A被唤醒,同步过程结束。

参考文章

Java并发编程之美

  • 16
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值