JAVA 多线程之信号量(Semaphore)实例详解

JAVA 多线程之信号量(Semaphore)实例详解

什么是信号量

信号量是操作系统中的一种同步工具,它可以用来控制同时访问某些资源的线程数量。Semaphore 是 Java 开发中一个用于控制线程的工具类,它可以用于控制同时执行的线程数量,可以看作是一种限流的方式。

Semaphore 所提供的计数器是被初始化的,并且该计数器有一个上限,它表示的是共享资源的个数。当某个线程需要访问共享资源时,它必须在这个 Semaphore 中占用一个许可(permit)。当许可被占用时,Semaphore 的计数器会减去 1,当计数器为 0 时,将不再允许执行占用许可的线程,其它的线程必须等待已下占用的线程释放许可。当占用许可的线程使用完共享资源后,它需要释放许可,这样 Semaphore 的计数器会加 1,表示又有一个许可可以被占用。

Semaphore 的使用

Semaphore 的常用方法主要有两个:acquire()release()

acquire() 方法用于申请一个许可,如果当前 Semaphore 的计数器大于 0,就可以申请许可,计数器值减 1。如果当前 Semaphore 的计数器为 0,调用 acquire() 方法的线程将一直阻塞,直到有许可可用为止。

release() 方法用于释放一个许可,计数器增加 1。

在使用 Semaphore 时,需要注意的是:申请和释放许可的线程必须是同一个线程。

示例一

下面是一个简单的示例,演示 Semaphore 的使用:

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2);  // 初始化信号量为 2
        new MyThread(semaphore, "A").start();
        new MyThread(semaphore, "B").start();
        new MyThread(semaphore, "C").start();
        new MyThread(semaphore, "D").start();
    }

    static class MyThread extends Thread {
        private Semaphore semaphore;

        public MyThread(Semaphore semaphore, String name) {
            super(name);
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();   // 获取许可
                System.out.println(Thread.currentThread().getName() + " 获取许可...");
                Thread.sleep(2000);  // 模拟线程执行任务需要占用许可
                semaphore.release();   // 释放许可
                System.out.println(Thread.currentThread().getName() + " 释放许可...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上面的示例中,我们创建了一个 Semaphore 对象,并将其初始值设置为 2。然后我们创建了 4 个线程,并将 Semaphore 对象传递给这些线程。在线程中,我们先尝试获取许可,如果获取到许可,则打印获取许可的信息,并模拟线程执行任务需要占用许可的时间;随后调用 release() 方法释放许可,并打印释放许可的信息。

运行该程序,输出如下:

A 获取许可...
C 获取许可...
C 释放许可...
D 获取许可...
A 释放许可...
D 释放许可...
B 获取许可...
B 释放许可...

从输出可以看出,同一时刻只有两个线程可以获取到许可,并且每个线程获得许可之后都需要释放许可,才能让其它线程获取许可。

示例二

下面是另外一个示例,演示使用 Semaphore 模拟某个共享资源的访问:

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);  // 初始化信号量为 3
        new ShareResource(semaphore, "A").start();
        new ShareResource(semaphore, "B").start();
        new ShareResource(semaphore, "C").start();
    }

    static class ShareResource extends Thread {
        private Semaphore semaphore;

        public ShareResource(Semaphore semaphore, String name) {
            super(name);
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " 尝试访问共享资源...");
                semaphore.acquire();   // 获取许可
                System.out.println(Thread.currentThread().getName() + " 成功访问共享资源");
                Thread.sleep(2000);  // 模拟线程执行任务需要占用许可
                semaphore.release();   // 释放许可
                System.out.println(Thread.currentThread().getName() + " 释放了许可");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在上面的示例中,我们创建了一个 Semaphore 对象,并将其初始值设置为 3。然后我们创建了 3 个线程,并将 Semaphore 对象传递给这些线程。在线程中,我们尝试获取许可,如果获取到许可,则打印成功访问共享资源的信息,并模拟线程执行任务需要占用许可的时间;随后调用 release() 方法释放许可,并打印释放许可的信息。

运行该程序,输出如下:

A 尝试访问共享资源...
A 成功访问共享资源
B 尝试访问共享资源...
B 成功访问共享资源
C 尝试访问共享资源...
C 成功访问共享资源
A 释放了许可
B 释放了许可
C 释放了许可

从输出可以看出,在同一时刻只有 3 个线程可以成功访问共享资源。每个线程访问共享资源之前都需要获取许可,访问结束后需要释放许可。如果没有许可可用,则线程会一直阻塞,直到有许可可用为止。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA 多线程之信号量(Semaphore)实例详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • WindowsXP终极优化设置大全

    WindowsXP终极优化设置大全攻略 WindowsXP作为一个经典的操作系统,在使用中可能存在一些不足之处,但是通过一些优化设置可以提升其性能和体验。本文将详细介绍WindowsXP终极优化设置大全的完整攻略,包括以下内容: 系统设置优化 软件程序优化 硬件驱动优化 网络优化设置 系统设置优化 1. 关闭无用的服务和应用程序 WindowsXP系统启动时…

    other 2023年6月28日
    00
  • VisualStudio页面怎么使用控件?

    要在VisualStudio中使用控件,可以按照以下步骤操作: 步骤1:打开工具箱 在VisualStudio中,可以通过在菜单栏中选择“View” -> “Toolbox”,或者按下快捷键Ctrl + Alt + X,来打开工具箱。 步骤2:选择控件 在工具箱中,可以看到各种可用的控件。可以直接使用工具箱中默认提供的控件,也可以自行添加自己编写的控件…

    other 2023年6月27日
    00
  • css绝对定位如何居中?css绝对定位居中的四种实现方法

    以下是关于“CSS绝对定位如何居中?CSS绝对定位居中的四种实现方法”的完整攻略,包含两个示例说明。 CSS绝对定位如何居中? 在CSS中,绝对定位元素默认相对于其最近的已定位祖先元素进行定位的。如果没有已定位的祖先元素,则相对于文档的初始含块进行定位。在本攻略中,我们将介绍如何将绝对定位元素居中。 1. 使用transform和负margin 我们可以使用…

    other 2023年5月9日
    00
  • ScriptManager 发送错误到客户端

    ScriptManager 发送错误到客户端的完整攻略 在 ASP.NET 中,可以使用 ScriptManager 控件将 JavaScript 代码发送到客户端。如果在服务器端发生错误,可以使用 ScriptManager 控件将错误信息发送到客户端。本文将为您提供一份 ScriptManager 发送错误到客户端的完整攻略,包括使用方法、操作步骤和两个…

    other 2023年5月5日
    00
  • jetty和netty有什么区别?

    jetty和netty有什么区别? jetty和netty都是Java网络编程框架,它们都提供了高性能、可扩展的网络编程解决方案。本文将详解jetty和netty的区别,包括设计思想、应用场景示例等内容。 设计思想 jetty和net的设计思想有所不同。jetty是基于servlet容器的,它的主要设计思想是提供一个完整的Web服务器,持servlet、JW…

    other 2023年5月8日
    00
  • win10系统怎么配置maven环境变量?

    当在Win10系统上进行Java开发时,需要使用Maven来管理项目依赖包,因此需要配置Maven的环境变量。 以下是配置Maven环境变量的步骤: 第一步:下载Maven 下载Maven压缩包,官方网站地址为:https://maven.apache.org/download.cgi 选择下载适合本机操作系统的Maven版本,本篇文档以Maven 3.8.…

    other 2023年6月27日
    00
  • vue开发者工具下载

    Vue开发者工具下载 Vue是一种流行的JavaScript框架,可用于构建大型的单页应用。在开发Vue应用过程中,Vue开发者工具是一个非常实用的工具,它可以帮助开发者进行调试和性能优化等工作。在本篇文章中,我们将介绍如何下载和安装Vue开发者工具。 下载Vue开发者工具 Vue开发者工具可以在官方网站上免费下载,官方网站的地址是 https://chro…

    其他 2023年3月28日
    00
  • rrmdir php中递归删除目录及目录下的文件

    在PHP中,我们可以使用rmdir函数来删除一个目录,但是该函数只能用于删除空目录。如果想要删除非空目录,我们需要使用rrmdir函数。 rrmdir函数可以采用递归方式删除目录及其下所有文件。它实际上是一个回调函数,我们可以在函数内部递归删除目录中的所有文件和子目录,直到整个目录结构被删除为止。下面是一个示例代码: function rrmdir($pat…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部