Semaphore

Semaphore用于控制同一时刻允许获取锁的线程个数。通过构造器Semaphore(int permits)来初始化许可数,如:

Semaphore s = new Semaphore(3),通过构造器传入3,此时s最多允许3个线程同时获取锁,在没有线程释放锁的情况下,其它线程只能等待。值得一提的是,如果许可数初始化为0,s = new Semaphore(0),此时并不代表所有线程都无法获取锁,如果其中某一个线程抢先执行了s.release(3),那么其它线程也可获取到锁,release(3)代表往Semaphore释放了3个许可,此时是的许可总数变为3,因此s又可以允许同时3个线程获取到锁。

Semaphore获取锁的方式可分为两种模式:

1.公平模式

此模式下一旦有线程释放锁,那么在等待队列中的线程会优先获取到锁,新来的想获取锁的线程将排在等待队列中的线程的后面,严格遵循先进先出原则。

2.非公平模式

此模式下一旦有线程释放锁,那么新来的线程有可能比等待队列中的线程抢先一步获取到锁,通俗地讲,新来的线程和等待队列中的线程处于同等地位,谁快谁抢到锁,抢占式的不遵循先进先出原则,因此属于非公平模式。

构造器:

//默认创建基于非公平模式,并指定初始许可数

1. public Semaphore(int permits)

//可以同时指定模式和初始许可数

2. public Semaphore(int permits, boolean fair)

public方法:

//获取一个许可(锁),成功获取反回,获取失败则等待,直到有可用锁或当前线程被中断后返回

3. public void acquire() throws InterruptedException

///获取一个许可(锁),成功获取反回,获取失败则等待,直到有可用锁后返回,此方法不响应中断

4. public void acquireUninterruptibly()

//尝试获取一个许可,成功反回true,失败返回false,非阻塞方法

5. public boolean tryAcquire()

//尝试获取一个许可,在等待时间内成功反回true,失败返回false

6. public boolean tryAcquire(long timeout, TimeUnit unit)

//尝试获取指定数量的许可,如果剩余许可数大于等于permits则成功返回,否则等待,直到有可用许可数或当前线程被中断后返回

7.  public void acquire(int permits) throws InterruptedException

//尝试获取指定数量的许可,如果剩余许可数大于等于permits则成功返回,否则等待,直到有可用许可数后返回,此方法不响应中断

8. public void acquireUninterruptibly(int permits)

//尝试获取指定数量的许可,如果剩余许可数大于等于permits则返回true,否则false

9. public boolean tryAcquire(int permits)

//尝试获取指定数量的许可,如果在等待时间内有剩余许可数大于等于permits则返回true,否则false

10. public boolean tryAcquire(int permits, long timeout, TimeUnit unit)

//释放一个许可(总许可数加1)

11. public void release()

//释放指定数量的许可(总许可数加permits)

12. public void release(int permits)

//返回当前可用许可总数,对于s = new Semaphore(0);s.release(3)那么返回许可总数是3!

13. public int availablePermits()

//将许可总数设置为0

14. public int drainPermits()

//是否是公平模式

15. public boolean isFair()

//是否有线程在等待队列中等待锁释放

16. public final boolean hasQueuedThreads()

//等待队列中等待获取锁的线程的数量

17. public final int getQueueLength()

protected方法:

//从总许可数中减去指定许可数reduction

1. protected void reducePermits(int reduction)

//返回等待队列中等待获取锁的线程实例

2. protected Collection<Thread> getQueuedThreads()

 


package java.util.concurrent;
import java.util.Collection;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;


public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;
    /** All mechanics via AbstractQueuedSynchronizer subclass */
    private final Sync sync;

    //主要继承模板类实现相关try方法(tryAcquireShared、tryReleaseShared)
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) {
            //通过AbstractQueuedSynchronizer内部提供的state整型属性保存许可数量
            //子类FairSync与NonfairSync构造器都会调用
            setState(permits);
        }
        //返回许可数
        final int getPermits() {
            return getState();
        }
        
        //非公平模式下尝试获取指定许可数
        final int nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    //比较再设置,防止其它线程已经修改了剩余许可数
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
        //释放指定数量的许可
        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;
            }
        }
        //减少许可总数
        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState();
                int next = current - reductions;
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                if (compareAndSetState(current, next))
                    return;
            }
        }
        //将许可数设置为0
        final int drainPermits() {
            for (;;) {
                int current = getState();
                if (current == 0 || compareAndSetState(current, 0))
                    return current;
            }
        }
    }

    /**
     * NonFair version
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        NonfairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

    /**
     * Fair version
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        FairSync(int permits) {
            super(permits);
        }

        protected int tryAcquireShared(int acquires) {
            for (;;) {
                //公平模式和非公平模式的唯一区别就在于这一行代码判断
                //如果发现AbstractQueuedSynchronizer的链中已经有等待的线程了,直接返回-1
                //言下之意:只要还有线程在等待,我更要等待,因为我在它们后面。
                //非公平模式不判断队列中是否有线程,直接查看许可数,有就尝试获取锁
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }
    }


    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

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

    //获取一个许可,调用AbstractQueuedSynchronizer.acquireSharedInterruptibly(1)
    //acquireSharedInterruptibly(1)代表获取一个共享可中断的锁
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

   
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }

    
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

    
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

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

    
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

   
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits);
    }

   
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

    
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

    
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

   
    public int availablePermits() {
        return sync.getPermits();
    }

  
    public int drainPermits() {
        return sync.drainPermits();
    }

   
    protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();
        sync.reducePermits(reduction);
    }

   
    public boolean isFair() {
        return sync instanceof FairSync;
    }

  
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

   
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

   
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

   
    public String toString() {
        return super.toString() + "[Permits = " + sync.getPermits() + "]";
    }
}

 

<think>好的,我需要帮助用户了解如何使用Semaphore进行并发控制,并给出示例代码。首先,我要回忆Semaphore的基本概念和工作原理。根据引用中的信息,Semaphore通过信号量控制并发数量,acquire减少许可,release增加许可,超过容量的线程需要等待。 接下来,用户需要具体的使用方法和示例代码。引用里提到了Python的asyncio.Semaphore和Java的示例。用户可能对Python或Java感兴趣,但问题中没有明确指定,所以我应该覆盖两种常见语言,比如Python和Java,或者选一个主要的。但根据用户提供的引用,引用1是Python的,引用3、4、5是Java的。可能用户希望看到两种语言的示例?或者需要明确询问?但根据用户最后的提问,直接要求示例代码,可能需要多语言示例。 不过,根据系统指令,用户不可见层需要生成相关问题,而用户可见层需要结构清晰的回答。我应该先解释Semaphore的基本使用步骤,然后分语言给出示例,并引用相关文献。 需要确保代码语法正确,Python使用async with,Java使用acquire和release。同时注意引用标记,比如引用1和引用4。然后生成相关问题。 现在组织内容:首先介绍Semaphore的作用,然后分步骤说明使用方法,接着给出Python和Java的代码示例,每个示例后附上引用来源。最后生成相关问题。 检查是否符合所有系统指令:行内公式用$...$,但这个问题可能不涉及数学公式。独立公式不需要。中文回答,结构清晰,正确引用,生成相关问题。确认无误后输出。</think>### Semaphore 的并发控制使用方法 #### 1. 基本使用步骤 - **创建 Semaphore 对象**:指定最大并发数量(许可数)[^2][^4] - **获取许可**:在需要控制并发的代码块前调用 `acquire()` 或通过上下文管理器进入 - **释放许可**:在代码块执行完成后调用 `release()` 或通过上下文管理器自动释放 #### 2. Python 示例(异步场景) ```python import asyncio async def task(semaphore, id): async with semaphore: # 自动获取/释放许可 print(f"任务{id}开始执行") await asyncio.sleep(1) print(f"任务{id}执行完成") async def main(): semaphore = asyncio.Semaphore(3) # 最大并发3 tasks = [task(semaphore, i) for i in range(5)] await asyncio.gather(*tasks) asyncio.run(main()) ``` *引用自异步编程实现[^1]* #### 3. Java 示例(线程同步) ```java import java.util.concurrent.Semaphore; public class Demo { private static final Semaphore semaphore = new Semaphore(3); // 最大并发3 public static void main(String[] args) { for (int i = 0; i < 5; i++) { new Thread(() -> { try { semaphore.acquire(); // 获取许可 System.out.println("任务开始:" + Thread.currentThread().getId()); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); // 释放许可 System.out.println("任务完成:" + Thread.currentThread().getId()); } }).start(); } } } ``` *引用自线程并发控制实现[^4]* #### 4. 关键机制 - 当许可耗尽时,后续线程进入阻塞状态 - 公平性可通过构造函数参数配置(Java 支持公平锁)[^4] - 支持尝试获取许可(`tryAcquire`)和超时机制[^5] §§ 相关问题 §§ 1. Semaphore 与 Mutex 锁有什么区别? 2. 如何防止 Semaphore 的许可泄漏问题? 3. Semaphore 在数据库连接池中的应用? 4. 如何实现 Semaphore 的跨进程控制? 5. Semaphore 的公平模式对性能有什么影响? : Python异步信号量实现 [^2]: Semaphore基础工作机制 : Java并发控制示例 : 单许可信号量实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值