Semaphore使用详解及源码解读

Semaphore在Java并发中用于控制对特定资源的并发访问,类似交通信号灯,初始化设置允许的线程数量。当线程调用acquire()获取许可并执行完毕后,必须调用release()释放资源。示例展示了4个线程尝试访问,只有3个能立即执行,后续线程需等待。Semaphore提供公平和非公平模式,并提供了检查资源状态的方法,如availablePermits()、hasQueuedThreads()等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

Semaphore(信号量)用来控制同时访问特定资源的线程数量,简单地说就是限流。
可以把它比作是控制流量的红绿灯,Semaphore的初始化大小就是可以通过的绿灯流量,达到设定值转红灯无法获得资源。当有一辆车驶出,就能有一辆车获得绿灯通过。车可以理解为线程。

使用acquire()方法获得通行,使用release()方法释放。方法tryAcquire()如果返回true的话也获得了通行,不过得自己释放。

示例

指定可通行数为3,使4个线程同时去,也只能有3个获得通行。
若释放一个线程,就可以有一个线程可获得通行。

package semaphore;

import java.util.concurrent.Semaphore;

/**
 * 可用来限流,控制同时访问特定资源的线程数量
 * 红绿灯,特定数量的线程看到的是绿灯,其他的看到红灯,线程结束后,特定数量线程看到绿灯
 * 可用于限制数据库连接
 * acquire获得许可,结束后需要release表示结束。tryAcquire尝试获取许可
 * 
 * @author bamboo
 *
 */
public class TestSemaphore {
	
	private static Semaphore s = new Semaphore(3);
	
	public static void main(String[] args) {
		for(int i = 0;i < 4;i++) {
			new Thread(new ThreadA(s)).start();
		}
		
		try {
			Thread.sleep(2000);
			s.release();
			System.out.println();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		for(int i = 0;i < 2;i++) {
			new Thread(new ThreadA(s)).start();
		}
		
		System.out.println(s.availablePermits());
		System.out.println(s.getQueueLength());
		System.out.println(s.hasQueuedThreads());
	}

}

如果成功获得通行就可以获得特定的资源,否则就去做其他的。

package semaphore;

import java.util.concurrent.Semaphore;

public class ThreadA implements Runnable{
	
	Semaphore semaphore;
	
	ThreadA(Semaphore semaphore){
		this.semaphore = semaphore;
	}
	
	@Override
	public void run() {
		
		try {
			if(semaphore.tryAcquire()) {
				Thread.sleep(1000);
				System.out.println(Thread.currentThread().getName() + " gets the green light");
			}else {
				Thread.sleep(1000);
				System.out.println(Thread.currentThread().getName() + " gets the red light");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

输出:

Thread-0 gets the green light
Thread-3 gets the red light
Thread-1 gets the green light
Thread-2 gets the green light

1
0
false
Thread-4 gets the green light
Thread-5 gets the red light

源码

如图可以看出Semaphore中抽象的静态内部类Sync,Sync继承自AQS队列同步器,AQS采用模板方法,自然Sync实现了一些父类方法。
Sync有两个子类,NonfairSync(非公平)和FairSync(公平版本子类)
niceHot

两个构造方法
默认构造方法是非公平的。

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and nonfair fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

此构造方法可以指定是否采用公平的方式。

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and the given fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     * @param fair {@code true} if this semaphore will guarantee
     *        first-in first-out granting of permits under contention,
     *        else {@code false}
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

acquire()方法
获取指定个数的许可证

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

获取一个许可证

    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(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 release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

是否有线程等待获取许可证

    /**
     * Queries whether any threads are waiting to acquire. Note that
     * because cancellations may occur at any time, a {@code true}
     * return does not guarantee that any other thread will ever
     * acquire.  This method is designed primarily for use in
     * monitoring of the system state.
     *
     * @return {@code true} if there may be other threads waiting to
     *         acquire the lock
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

返回正在等待获取许可证的线程数

    /**
     * Returns an estimate of the number of threads waiting to acquire.
     * The value is only an estimate because the number of threads may
     * change dynamically while this method traverses internal data
     * structures.  This method is designed for use in monitoring of the
     * system state, not for synchronization control.
     *
     * @return the estimated number of threads waiting for this lock
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

返回此信号量中当前可用的许可证

  /**
     * Returns the current number of permits available in this semaphore.
     *
     * <p>This method is typically used for debugging and testing purposes.
     *
     * @return the number of permits available in this semaphore
     */
    public int availablePermits() {
        return sync.getPermits();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值