Java中的Semaphore如何使用

使用 Semaphore 可以控制同时访问资源的线程个数,在 Java 中,Semaphore 是一个计数信号量。

Semaphore 可以用来限制某个资源的访问线程个数,它的构造函数接收一个整型变量 n,表示同一时刻最多允许 n 个线程访问该资源。当一个线程进入该资源进行访问时,计数器会减去 1,其他线程再访问时就会被阻塞,直到该线程释放资源时计数器加 1。Semaphore 可以控制资源的访问数量,是一个非常重要的并发控制工具。

Semaphore 类的基本用法

Semaphore 类是 Java.util.concurrent 包下的类,使用它需要导入以下包:

import java.util.concurrent.Semaphore;

Semaphore 类的构造器、方法参数都是 int 型的,说明 Semaphore 可以协调的线程数量必须是整数类型,解决某一个范围的访问问题。

Semaphore 类有以下方法:

  • acquire(): 获取一个许可证,如果没有可用的许可证,则会阻塞直到有可用的许可证;
  • release(): 释放一个许可证,释放一个阻塞的线程;
  • tryAcquire(): 尝试获取一个许可证,并立即返回 true 或 false;
  • tryAcquire(long timeout, TimeUnit unit): 在指定的时间内尝试获取一个许可证;
  • availablePermits(): 获取当前可用的许可证数量。

简单示例:

下面的代码简单演示了如何使用 Semaphore,假设有 10 个资源,现在有 30 个线程需要访问这 10 个资源,每次只能有 3 个线程同时访问,其他线程需要等待当前 3 个线程访问完后才能访问。

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); // 初始化信号量,最多允许 3 个线程访问
        for (int i = 0; i < 30; i++) {
            Thread t = new Thread(() -> {
                try {
                    semaphore.acquire(); // 获取一个许可证
                    System.out.println(Thread.currentThread().getName() + "开始访问资源");
                    Thread.sleep(2000); // 模拟访问资源需要 2s
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // 释放一个许可证
                    System.out.println(Thread.currentThread().getName() + "结束访问资源");
                }
            }, "Thread-" + i);
            t.start();
        }
    }
}

该示例会启动 30 个线程,每个线程尝试去获取一个许可证,当许可证数量不足时,线程会被阻塞,直到获取到许可证后才能继续执行,然后线程释放许可证并结束访问。

Semaphore 与 Condition 一起使用

Semaphore 与 Condition 可以协同工作,Semaphore 负责控制线程的并发访问数量,Condition 负责控制线程的等待和通知,这样可以实现更复杂的并发控制。下面的示例演示了 Semaphore 和 Condition 一起使用的方法。

假设现在有两个线程,线程 1 执行任务 A,线程 2 执行任务 B,任务 B 需要依赖任务 A 的结果,在任务 A 执行完后通知任务 B 开始执行。

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SemaphoreWithConditionDemo {
    private static final Semaphore semaphore1 = new Semaphore(1);
    private static final Semaphore semaphore2 = new Semaphore(0);

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread-1执行任务A");
                Thread.sleep(2000);
                condition.signal(); // 通知线程 2 执行任务B
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "Thread-1");

        Thread t2 = new Thread(() -> {
            semaphore1.acquire(); // 获取 semaphore 1 的许可证
            lock.lock();
            try {
                System.out.println("Thread-2等待Thread-1执行完任务A,开始执行任务B");
                Thread.sleep(2000);
                semaphore2.release(); // 释放 semaphore 2 的许可证
                System.out.println("Thread-2执行完任务B");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "Thread-2");

        t2.start();
        t1.start(); // 等待线程 1 完成任务 A,通知线程 2 执行任务 B
        lock.lock();
        try {
            condition.await(); // 等待线程 1 完成任务 A
            System.out.println("Thread-1执行完任务A,通知Thread-2执行任务B");
            semaphore1.release(); // 释放 semaphore 1 的许可证
            semaphore2.acquire(); // 获取 semaphore 2 的许可证
            System.out.println("Thread-1继续执行任务");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

该示例会启动两个线程,线程 1 执行任务 A,线程 2 等待线程 1 执行完任务 A 后执行任务 B,任务 B 需要依赖任务 A 的结果,当任务 A 完成后通知线程 2 开始执行任务 B。实现该示例需要使用 Semaphore 和 Condition 类,Semaphore 的作用是限制同时执行任务的线程数量,Condition 用于通知线程 2 开始执行任务 B。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中的Semaphore如何使用 - Python技术站

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

相关文章

  • Java中的拦截器、过滤器、监听器用法详解

    Java中的拦截器、过滤器、监听器用法详解 Java中的拦截器、过滤器、监听器是Web开发中常用的几种组件,它们可以用于拦截、修改请求和响应、监听特定事件等。本文将详细讲解它们的用法。 过滤器(Filter) 在Java Web应用中,过滤器可以用于拦截请求和响应,这使得过滤器非常有用,能够实现很多功能,例如:HTTP缓存、字符编码、安全等。 以下是一个过滤…

    Java 2023年6月15日
    00
  • 亲测有效解决Tomcat启动提示错误:At least one JAR was scanned for TLDs yet contained no TLDs

    首先,这个错误信息提示我们Tomcat扫描到了至少一个JAR文件,但是该JAR文件中没有包含任何的TLD文件。在这种情况下,Tomcat就无法识别出该JAR文件中的标签库,最终导致启动失败。 下面是解决这个问题的攻略步骤: 对于直接使用Tomcat的用户 可以在启动Tomcat之前,在Tomcat根目录下的conf目录找到Catalina/localhost…

    Java 2023年6月2日
    00
  • Java多线程常见案例分析线程池与单例模式及阻塞队列

    Java多线程常见案例分析线程池与单例模式及阻塞队列攻略 什么是多线程? 在计算机科学中,多线程(英语:Multithreading)指的是同时运行多个线程执行不同的任务。在线程中,单个处理器(或核心)会执行多个并发执行的任务。这是在现代操作系统中实现并发的一种方式。 什么是线程池? 线程池是预先实例化一定数量的线程,并在它们启动时将它们放入池中。每个任务都…

    Java 2023年5月19日
    00
  • Java 使用JdbcTemplate 中的queryForList发生错误解决办法

    让我来详细讲解“Java 使用JdbcTemplate 中的queryForList发生错误解决办法”的完整攻略。 问题描述 在使用JdbcTemplate的queryForList方法查询数据时,有时候会出现错误,例如: org.springframework.dao.InvalidDataAccessApiUsageException: You need…

    Java 2023年6月16日
    00
  • Ubuntu 16.04安装Apache Tomcat的方法

    下面是Ubuntu 16.04安装Apache Tomcat的具体步骤: 步骤一:安装Java环境 在Ubuntu 16.04中,可以通过以下命令安装Java环境: sudo apt-get update sudo apt-get install default-jdk 安装成功后,可以通过以下命令验证Java版本信息: java -version 示例输出…

    Java 2023年5月19日
    00
  • springboot maven 打包插件介绍及注意事项说明

    Spring Boot Maven打包插件介绍 Spring Boot使用了Maven作为构建工具,通过Maven进行项目的编译、依赖管理和打包部署等操作,其中Maven的打包插件在Spring Boot中有着非常重要的作用。 Maven的打包插件主要用于将项目打成可执行的JAR或WAR包,Spring Boot将其进一步封装为了一些特定的插件,以适应Spr…

    Java 2023年6月2日
    00
  • java如何使用Lombok更优雅地编码

    Java开发中,有很多操作都是重复而无聊的,例如get/set方法的编写。通过使用Lombok,可以在编码时更加优雅,省去这些重复的部分。下面是Java如何使用Lombok更优雅地编码的完整攻略: 1. 安装Lombok 首先在Maven中,添加Lombok的依赖: <dependency> <groupId>org.projectl…

    Java 2023年5月20日
    00
  • 使用java连接Redis,Maven管理操作

    使用Java连接Redis,本质上是通过Redis的Java客户端来实现。Java开发者可以通过Maven来管理Redis的Java客户端相关依赖,使开发变得更加简单高效。下面,我们将详细介绍如何使用Java连接Redis以及如何通过Maven管理Redis相关依赖。 第一步:引入Redis Java客户端依赖 要使用Java连接Redis,首先需要在Jav…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部