云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

什么是Java中的Semaphore?详细介绍一下?

jxf315 2024-12-26 14:08:55 教程文章 34 ℃

Semaphore(信号量)是在Java中的一种用来控制多线程访问共享资源的同步机制。提供了一种通用的、灵活的信号量控制机制,用于限定对特定共享资源的访问线程数。是一种比较经典的并发控制工具,它适用于多线程限定共享资源访问数量的场景中,例如数据库连接池、文件读写操作、或者是在一些网络连接控制的场景中都可以使用。

Semaphore的基本概念

在操作系统中,信号量是一种计数器,用于记录可以访问某资源的线程数量。而在Java中Semaphore通过维护一个计数器permits来记录可以提供给当前线程使用的资源数。

当线程试图访问受限资源时,需要先调用acquire()方法获取一个许可。如果当前许可数量大于0,则获取许可并将计数器减1。否则就是获取不到访问许可就无法进行访问。

当线程释放资源时,通过调用release()方法将许可归还,将计数器加1。提供后续的服务进行调用。

Semaphore的构造方法

在Semaphore提供了两种主要的构造方法,如下所示。

  • Semaphore(int permits): 创建一个指定许可数 permits 的信号量,默认为非公平模式。
  • Semaphore(int permits, boolean fair): permits 参数指定信号量的许可数,fair 参数指定是否使用公平策略。

在公平模式下,线程会按照先后顺序排队获取许可,适用于对等待时间较为敏感的场景。然而,公平模式可能会带来较大的线程调度开销,导致吞吐量下降。而非公平模式下,线程可以随机获取许可,这样可以减少线程切换开销,提高吞吐量。在高并发、且不太在意访问公平性的场景中,通常选择非公平模式。

Semaphore的主要方法

  • void acquire(): 获取一个许可,如果没有许可,则阻塞直到有许可为止。
  • void acquire(int permits): 获取指定数量的许可,如果没有足够的许可,则阻塞。
  • void release(): 释放一个许可,将信号量的许可数加 1。
  • void release(int permits): 释放指定数量的许可,将信号量的许可数增加 permits。
  • int availablePermits(): 返回当前可用的许可数量。
  • boolean tryAcquire(): 尝试获取一个许可,如果有许可则获取并返回 true,否则返回 false。
  • boolean tryAcquire(long timeout, TimeUnit unit): 尝试在指定的时间内获取许可,获取成功返回 true,否则返回 false。

示例代码

假设我们有一个资源池,最多允许三个线程同时访问该资源,其他线程则必须等待。我们可以可以通过Semaphore实现对其的控制管理,如下所示。

import java.util.concurrent.Semaphore;

public class ResourcePool {
    private final Semaphore semaphore;

    public ResourcePool(int maxPermits) {
        this.semaphore = new Semaphore(maxPermits);
    }

    public void accessResource() {
        try {
            semaphore.acquire();  // 获取一个许可
            System.out.println(Thread.currentThread().getName() + " 正在访问资源");
            Thread.sleep(2000);   // 模拟资源访问
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            System.out.println(Thread.currentThread().getName() + " 释放资源");
            semaphore.release();  // 释放许可
        }
    }

    public static void main(String[] args) {
        ResourcePool pool = new ResourcePool(3); // 资源池最多允许3个线程同时访问

        for (int i = 0; i < 10; i++) {
            new Thread(pool::accessResource).start();
        }
    }
}

在上面代码中创建了一个Semaphore,并设定最多同时允许3个线程访问资源。然后再主线程中启动了10个子线程,并且每个线程都试图访问共享资源。当前三个线程立即获得许可并开始访问资源,而其他线程会被阻塞禁止访问,当当一个线程访问完资源并调用 release() 后,另一个等待的线程会获得许可并开始执行。

总结

Semaphore是一种非常有用的并发工具,在需要控制资源访问数量时,可以有效地避免过多线程导致资源耗尽。通过合理设置许可数量和公平模式,Semaphore可以根据业务需求优化资源管理。

最近发表
标签列表