Java并发(10)——Semaphore

本文详细介绍了Java并发工具Semaphore的作用、使用场景和设计思想,并通过实例展示了其工作原理。Semaphore用于限制对资源的并发访问,类似于线程间的信号灯,可以控制同时访问特定资源的线程数量。文章还深入剖析了Semaphore的源码,包括非公平锁和公平锁的实现,以及加锁、释放锁的逻辑。通过对Semaphore的理解,读者可以更好地掌握Java并发编程中的线程同步机制。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


作用

对访问某个资源的线程数量进行控制,若访问线程数量大于规定数量,后面来的全部阻塞。

例如:厕所一共只有10个坑位。。那么只能同时10个人用着,后面来的人都得等着(阻塞),如果走了2个人,那么又可以进去2个人

使用

Semaphore 维护最大访问线程数量为2,一个创建5个线程。只有2个能加锁执行,剩余3个等待。直到加锁线程释放锁 。

public class Main{
   public static void main(String[] args) {
      Semaphore semaphore = new Semaphore(2);
      for(int i=0;i<5;i++){
         new Thread(new Runnable() {
            @Override
            public void run() {
               try {
                  semaphore.acquire();
                  System.out.println(Thread.currentThread().getName()+"开始执行");
                  Thread.sleep(2000);
                  System.out.println(Thread.currentThread().getName()+"执行完毕");
                  semaphore.release();
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         },i+"").start();
      }
   }
}
1开始执行
0开始执行
0执行完毕
1执行完毕
3开始执行
2开始执行
2执行完毕
3执行完毕
4开始执行
4执行完毕

设计思想

基于aqs实现
(0)共享模式,进入同步代码块的线程可以有多个
(1)state表示当前还有几个许可证
(2)重写了AQS中tryAcquireShared()、tryReleaseShared(),根据Semaphore自身特性重新定义了竞争锁、释放锁的策略

自身特性如下:

state>0 表示许可证数量,此时线程将state-1,成功竞争锁
state<=0 表示阻塞线程数量,此时线程将state-1,自己阻塞。

(4)所有等待节点以共享模式阻塞,每次唤醒,唤醒全部阻塞结点

源码分析

Semaphore初始化

默认非公平锁,可设置

指定了许可线程数量,permits赋值给state

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

根据自身特性重写方法

acquires表示当前线程所要申请的许可证数量,默认为1。

将当前已有的许可证数量-线程申请的数量,如果结果<0 表示申请失败,该线程阻塞

非公平锁

        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;
            }
        }

公平锁,比非公平多了一个判断队列是否有人的机制

        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;
            }
        }

释放锁资源,将state+1,表示许可证数量+1

    public void release() {
        sync.releaseShared(1);
    }
        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()加锁

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

tryAcquireShared(arg) < 0 表示许可证数量<0 ,此时线程排队

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

线程调用release()解锁,释放许可证成功后,立即唤醒阻塞线程

    public void release() {
        sync.releaseShared(1);
    }
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值