Java中的Semaphore如何使用

yizhihongxing

使用 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实现301永久重定向方法

    Java实现301永久重定向的方法需要在服务器端进行配置。下面是具体的步骤: 1. 配置web.xml文件 在web.xml文件中添加以下代码,该代码将对匹配的URL进行永久重定向 <web-app> <error-page> <error-code>301</error-code> <location&…

    Java 2023年6月15日
    00
  • Java中关于char类型变量能够输出中文的问题

    Java中的char类型变量能够输出中文,是因为Java使用的是Unicode字符编码标准,其中全球所有的字符都有唯一的码位,包括中文字符。在Java中,char类型变量以16位无符号整数形式存储字符。由于Unicode字符集在编码范围内包含了中文字符,所以Java的char类型变量和String类型能将中文字符完美输出。 在Java中,对于char类型变量…

    Java 2023年5月26日
    00
  • JavaScript数据类型和变量_动力节点Java学院整理

    JavaScript数据类型和变量攻略 JavaScript数据类型 JavaScript有七种数据类型:数字(Number)、字符串(String)、布尔(Boolean)、对象(Object)、空(Null)、未定义(Undefined)和Symbol(符号) 使用typeof操作符可以检测数据类型 // 检测数字类型 typeof 123 //输出 &…

    Java 2023年5月26日
    00
  • jabsorb笔记_几个小例子第1/2页

    jabsorb笔记_几个小例子第1/2页 什么是jabsorb jabsorb是一个 JavaScript 对象表示法 (JSON) 库,它将 Java 对象转换为 JSON 格式并反向转换。它具有很高的效率和灵活性,并且易于使用。 jabsorb的使用方法 jabsorb的使用非常简单,只需要引入jabsorb的jar包,然后创建一个JSONRPCBrid…

    Java 2023年6月15日
    00
  • jsp读取数据库实现分页技术简析

    下面我将详细讲解“jsp读取数据库实现分页技术简析”的完整攻略。 什么是分页技术 在Web应用程序中,由于数据量庞大,为了方便用户查看,需要将这些数据进行分页展示。分页技术,就是将大量数据按照一定规则分割成若干页,进行分页展示,方便用户查看和操作。 实现分页技术的步骤 实现分页技术需要经过以下几个步骤: 第一步:数据库查询 首先,我们需要将所有数据从数据库中…

    Java 2023年6月15日
    00
  • 解决mybatis 数据库date 与 java中Date类型映射问题

    解决mybatis 数据库date 与 java中Date类型映射问题可以通过以下步骤: 1. 增加日期类型转换器 在mybatis的配置文件中,我们可以增加一个类型转换器,将数据库中的date类型转换为Java中的Date类型。在mybatis-config.xml文件中增加如下代码: <typeHandlers> <typeHandle…

    Java 2023年5月20日
    00
  • Java深入探究Object类的方法

    Java深入探究Object类的方法 Object类是Java中最基础的类,所有Java类都是从Object类继承而来的。Object类定义了Java中通用的方法,然而许多Java程序员并不能完整地掌握Object类的方法,这不仅仅是一个缺陷,更是对Java理解的不足。本篇文章将为您详细讲解Java深入探究Object类的方法,包括常用方法,继承关系,equ…

    Java 2023年5月26日
    00
  • Springmvc和ajax如何实现前后端交互

    在 Web 开发中,前后端交互是非常重要的。Spring MVC 和 Ajax 可以很好地实现前后端交互。本文将详细讲解 Spring MVC 和 Ajax 如何实现前后端交互的完整攻略,并提供两个示例说明。 1. Spring MVC 和 Ajax 简介 Spring MVC 是一个基于 Java 的 Web 框架,它可以帮助我们构建 Web 应用程序。A…

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