Java并发编程Semaphore计数信号量详解

yizhihongxing

Java并发编程Semaphore计数信号量详解

介绍

Semaphore(信号量)是一个经典的并发编程工具,被广泛应用于各种应用场景,如资源池、限流等。Semaphore 给予我们对并发调度这个宏观的掌控权。

在 Java 5 中,Semaphore 正式被纳入了 Java 并发包,并成为了并发编程中一个必不可少的类。Semaphore 是一个计数信号量,它可以限制同时访问某个资源或者某段代码的线程数量。Semaphore 用于控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理地使用资源。

使用

创建 Semaphore

Semaphore 的创建非常简单,只需要指定信号量的许可数量即可完成。

Semaphore semaphore = new Semaphore(1); // Semaphore 许可数为1

创建一个 Semaphore 实例后,就可以进行 acquire 和 release 操作了。

acquire

acquire(获取许可)方法:当一个线程调用 acquire 操作时,它要么通过获取许可成功获取 Semaphore 许可证,要么一直等下去,直到有许可证可用。Semaphore 有一个许可计数,每调用一次 acquire() 方法许可计数减一,如果计数为零,那么将会等待其他线程释放许可证。

public void acquire() throws InterruptedException
public void acquire(int permits) throws InterruptedException

release

release(释放许可)方法:每调用一次 release() 方法许可证计数加一,然后释放该许可证,以使其可用于其他等待信号量许可证的线程。如果有任何线程试图获取一个许可证,一个释放的许可证将会使它得到许可证,即释放许可证的线程不一定是同一个会获取许可证的线程。

public void release()
public void release(int permits)

示例1

场景:多个线程访问某个资源,但同时只允许两个线程访问。

public class AccessResource {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            Runnable runnable = () -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " access the resource");
                    Thread.sleep(2000);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();
    }
}

在上述代码中,创建了一个 Semaphore,许可数量为 2,表示同一时间只有两个线程能够访问资源。然后创建线程池并执行任务。每个任务对Semaphore进行 acquire 和 release 操作,确保同一时间最多只有两个线程能够访问该资源。

示例2

场景:通过 Semaphore 实现简单的限流。

public class RateLimit {
    public static void main(String[] args) {
        RateLimiter rateLimiter = RateLimiter.create(2);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            Runnable runnable = () -> {
                if (rateLimiter.tryAcquire()) {
                    System.out.println(Thread.currentThread().getName() + " get the access");
                } else {
                    System.out.println(Thread.currentThread().getName() + " rate limit");
                }
            };
            executorService.execute(runnable);
        }
        executorService.shutdown();
    }
}

在上述代码中,使用了一个叫做 RateLimiter 的开源框架实现了限流功能。在使用中通过 Semaphore 控制许可数量,调用 tryAcquire 方法尝试获取许可,如果获取到了就可以进行操作,否则就是限流操作。

总结

Semaphore 是非常常用的工具类,可以方便地实现对资源的控制和访问。需要注意 Semaphore 计数语义和其中与 Mutex 和 ReentrantLock 比较相似的 tryAcquire 方法存在的区别。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java并发编程Semaphore计数信号量详解 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • C#多线程系列之线程通知

    C#多线程系列之线程通知主要涵盖三个部分:Monitor、AutoResetEvent和ManualResetEvent。 Monitor 在C#中,Monitor类是一种基本的同步机制,支持两种操作:Enter()和Exit()。Enter()用于请求获取对象的锁,而Exit()用于释放对象的锁,最终达到线程同步的目的。 Monitor类的典型应用场景是在…

    多线程 2023年5月17日
    00
  • 详解Java并发包中线程池ThreadPoolExecutor

    详解Java并发包中线程池ThreadPoolExecutor的完整攻略 什么是线程池 线程池是一种线程调度方式,将线程的创建,销毁和调度等细节都交给线程池来管理,从而大大减少了线程数量过多造成的性能问题。 ThreadPoolExecutor类的介绍 ThreadPoolExecutor是Java并发包中提供的线程池实现类,它支持多种线程池执行策略,且还允…

    多线程 2023年5月17日
    00
  • 浅谈Redis高并发缓存架构性能优化实战

    浅谈Redis高并发缓存架构性能优化实战 一、前言 随着互联网的发展,访问量的激增,如何提高网站的响应速度,增加网站的并发能力成为了大家关注的热点。而Redis作为高性能缓存数据库,成为了缓存业务的首选。 在实际开发中,Redis高并发缓存架构的性能优化是非常重要的,本文将结合实战经验,浅谈Redis高并发缓存架构性能优化的几个方面。 二、Redis高并发缓…

    多线程 2023年5月17日
    00
  • Java多线程并发生产者消费者设计模式实例解析

    Java多线程并发生产者消费者设计模式是一种常见的并发编程模式,它可以让生产者不停地生产数据,消费者不停地消费数据,从而实现高效的数据处理。下面,我将分为以下几个步骤详细讲解Java多线程并发生产者消费者设计模式实例解析。 1.生产者消费者设计模式的原理 生产者消费者设计模式是一种基于阻塞队列的并发模式。它的基本思想是,将生产者线程和消费者线程分别放在不同的…

    多线程 2023年5月17日
    00
  • 详解Java多线程和IO流的应用

    详解Java多线程和IO流的应用 简介 Java多线程和IO流是Java编程中非常重要的两个主题。多线程可以帮助我们充分利用计算机多核处理器的性能,从而提高程序运行效率。而IO流则可以帮助我们进行文件读写、网络通信等操作。本文将从基础概念讲解和实际例子两个方面介绍Java多线程和IO流的应用。 基础概念讲解 多线程 Java多线程是指在同一时刻,多条线程同时…

    多线程 2023年5月17日
    00
  • Java 实现多线程的几种方式汇总

    Java 实现多线程的几种方式汇总 在 Java 编程中使用多线程是非常常见的需求,本文将汇总几种常见的 Java 多线程实现方式,帮助读者实现多线程编程。 1. 继承Thread类 使用 Thread 类并重写 run() 方法是创建一个新线程的最简单方法。以下是创建线程的步骤: 定义 Thread 的子类并重写 run() 方法。 创建 Thread 的…

    多线程 2023年5月17日
    00
  • Spring事务处理Transactional,锁同步和并发线程

    我来为你详细讲解一下“Spring事务处理Transactional,锁同步和并发线程”的完整攻略。 Spring事务处理Transactional Spring的事务管理器提供了一种方便的方式来处理数据库的事务。对于需要保证数据库操作的原子性(ACID)的业务操作,我们常常使用Spring的@Transactional注解。 在一个Spring管理的bea…

    多线程 2023年5月17日
    00
  • java 线程池的实现原理、优点与风险、以及4种线程池实现

    当我们处理大量任务的时候,线程池是一种常用的解决方案,使用线程池可以控制线程数量,提高效率,避免线程频繁创建和销毁的开销。本文就来详细讲解Java线程池的实现原理、优点与风险以及四种线程池实现。 Java线程池的实现原理 Java线程池的实现原理是基于线程池的管理器、工作线程、任务队列三部分来完成。线程池的管理器负责管理线程池的状态、任务分发、工作线程的创建…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部