JUC并发包—Semaphore

目录

Semaphore是什么

Semaphore的常用方法

semaphore.acquire();

semaphore.release();

Semaphore的内部原理

NonfairSync和FairSync有什么区别?


Semaphore是什么

  • 信号量的意思,
  • 在操作系统中用来表示系统中某种资源的数量,
  • 在Java中则可以用来限制同时访问共享资源的线程上限

Semaphore的常用方法

semaphore.acquire();

当调用 acquire方法时线程就会被阻塞,直到Semaphore中可以获得到许可证为止,然后线程再获取这个许可证。 

semaphore.release();

当调用release方法时将向Semaphore中添加一个许可证,如果有线程因为获取许可证被阻塞时,它将获取到许可证

代码演示

//测试类
public class Student implements Runnable {

    private String name;
    private Semaphore semaphore;

    public Student(String name, Semaphore semaphore) {
        this.name = name;
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        try {
            Random random = new Random();
            semaphore.acquire();
            System.out.println( name+  "开始吃饭");
            Thread.sleep((long) (random.nextDouble() * 5000) + 2000);
            System.out.println( name + " 吃饭完成OVER");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//主方法
public class Test {
    public static void main(String[] args) {

        Semaphore semaphore = new Semaphore(1);
        ArrayList<Thread> arrayList = new ArrayList<>();
        arrayList.add(new Thread(new Student("1号",semaphore)));
        arrayList.add(new Thread(new Student("2号",semaphore)));
        arrayList.add(new Thread(new Student("3号",semaphore)));
        arrayList.add(new Thread(new Student("4号",semaphore)));
        arrayList.add(new Thread(new Student("5号",semaphore)));

        for(Thread thread:arrayList){
            thread.start();
        }
    }
}

//输出结果
2号开始吃饭
2号 吃饭完成OVER
1号开始吃饭
1号 吃饭完成OVER
5号开始吃饭
5号 吃饭完成OVER
4号开始吃饭
4号 吃饭完成OVER
3号开始吃饭
3号 吃饭完成OVER

以上实例不会按照线程启动的,默认调用非公平锁的构造方法,如果需要按照线程顺序启动,调用Semaphore的公平锁构造方法

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

使用上加true,这样使用的是FairSync(公平锁),可以确保按照各个线程调用acquire方法的顺序获得许可证。

 Semaphore semaphore = new Semaphore(1,true);

Semaphore的内部原理

  • Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理。
  • Semaphore在构造时,需要传入许可证的数量,它最后传递给了AQS的state值。
  • 线程在调用acquire方法获取许可证时,如果Semaphore中许可证的数量大于0,许可证的数量就减1,线程继续运行,如果获取许可证时,Semaphore中许可证的数量为0,则获取失败,线程进入AQS的等待队列中,等待被其它释放许可证的线程唤醒。
  • 当线程运行结束调用release方法时释放许可证时,许可证的数量就加1。

NonfairSync和FairSync有什么区别?

NonfairSync的acquire源码

   final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

Release源码(许可证加1)

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

FairSync的acquire源码

protected int tryAcquireShared(int acquires) {
    for (;;) {
    	//检查阻塞队列中是否有等待的线程
        if (hasQueuedPredecessors())
            return -1;
        int available = getState();

        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

当一个线程A调用acquire方法时,会直接尝试获取许可证,而不管同一时刻AQS阻塞队列中是否有线程也在等待许可证,如果恰好有线程C调用release方法释放许可证,并唤醒阻塞队列中第一个等待的线程B,此时线程A和线程B是共同竞争可用许可证,不公平性就体现在:线程A没任何等待就和线程B一起竞争许可证了。

和非公平策略相比,FairSync是否在AQS阻塞队列线程中的检查,如果在,就可以参与许可证的竞争;如果不在,线程直接被插入到阻塞队列尾节点并挂起,等待被唤醒。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值