Semaphores 怎样工作?

您可以将信号量看做可以递增或递减的计数器。用一个数字即5来初始化信号量。现在这个信号量可以连续最多递减五次,直到计数器达到0.一旦计数器为零,你可以将它增加到最多五次使其成为5。计数器值信号量必须始终在内部限制0> = n> = 5(在我们的例子中)。

显然,信号量不仅仅是计数器。当计数器值为零时,它们能够使线程等待,即它们充当具有计数器功能的锁。

谈到多线程,当一个线程想要访问一个共享资源(由信号量保护)时,首先,它必须获取信号量。如果信号量的内部计数器大于0,则信号量递减计数器并允许访问共享资源。否则,如果信号量的计数器为0,则信号量将线程置于休眠状态,直到计数器大于0。计数器中的值0表示所有共享资源都被其他线程使用,因此,如果线程想要使用共享资源中的一个,就必须等待到其中一个空闲。

 注意:当线程完成共享资源的使用时,它必须释放信号量,以便其他线程可以访问共享资源。 该操作增加信号量的内部计数器。

怎样使用semaphore?

为了演示这个概念,我们将使用信号量来控制可以同时打印多个文档的3台打印机。

PrintingJob.java

此类表示可以提交到打印机队列的独立打印作业。 从队列中,它可以被任何打印机拾取并执行打印作业。 这个类实现了Runnable接口,这样打印机就可以在轮到它时执行它。

class PrintingJob implements Runnable {
private PrinterQueue printerQueue; public PrintingJob(PrinterQueue printerQueue) {
this.printerQueue = printerQueue;
} @Override
public void run() {
System.out.printf("%s: Going to print a document\n", Thread
.currentThread().getName());
printerQueue.printJob(new Object());
}
}

PrinterQueue.java

此类表示打印机队列/打印机。 该类有3个主要属性,用于控制从3台打印机中选择一台空闲打印机的逻辑,并将其锁定以打印作业。 打印文档后,将释放打印机,使其再次空闲并可用于从打印队列中打印新作业。

此类有两个方法getPrinter()和releasePrinter(),它们负责获取空闲打印机和将其放回空闲打印机池中。

另一个方法printJob()实际上做核心工作,即获取打印机,执行打印作业,然后释放打印机。

它使用以下两个变量来完成工作:

semaphore:这个变量记录跟踪在任何时间正在使用的打印机数量。
printerLock:用于在从三台可用打印机中检查/获取免费打印机之前锁定打印机池。

class PrinterQueue
{
//This Semaphore will keep track of no. of printers used at any point of time.
private final Semaphore semaphore; //While checking/acquiring a free printer out of three available printers, we will use this lock.
private final Lock printerLock; //This array represents the pool of free printers.
private boolean freePrinters[]; public PrinterQueue()
{
semaphore = new Semaphore(3);
freePrinters = new boolean[3];
for (int i = 0; i < 3; i++) {
freePrinters[i] = true;
}
printerLock = new ReentrantLock();
} public void printJob(Object document)
{
try
{
//Decrease the semaphore counter to mark a printer busy
semaphore.acquire(); //Get the free printer
int assignedPrinter = getPrinter(); //Print the job
Long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName()
+ ": Printer " + assignedPrinter
+ " : Printing a Job during " + (duration / 1000)
+ " seconds :: Time - " + new Date());
Thread.sleep(duration); //Printing is done; Free the printer to be used by other threads.
releasePrinter(assignedPrinter);
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
System.out.printf("%s: The document has been printed\n", Thread
.currentThread().getName()); //Increase the semaphore counter back
semaphore.release();
}
} //Acquire a free printer for printing a job
private int getPrinter()
{
int foundPrinter = -1;
try {
//Get a lock here so that only one thread can go beyond this at a time
printerLock.lock(); //Check which printer is free
for (int i = 0; i < freePrinters.length; i++)
{
//If free printer found then mark it busy
if (freePrinters[i])
{
foundPrinter = i;
freePrinters[i] = false;
break;
}
}
}
catch (Exception e) {
e.printStackTrace();
} finally
{
//Allow other threads to check for free priniter
printerLock.unlock();
}
return foundPrinter;
} //Release the printer
private void releasePrinter(int i) {
printerLock.lock();
//Mark the printer free
freePrinters[i] = true;
printerLock.unlock();
}
}

我们来测试打印机程序:

public class SemaphoreExample
{
public static void main(String[] args)
{
PrinterQueue printerQueue = new PrinterQueue();
Thread thread[] = new Thread[10];
for (int i = 0; i < 10; i++)
{
thread[i] = new Thread(new PrintingJob(printerQueue), "Thread " + i);
}
for (int i = 0; i < 10; i++)
{
thread[i].start();
}
}
} Output: Thread 1: Going to print a document
Thread 4: Going to print a document
Thread 9: Going to print a document
Thread 8: Going to print a document
Thread 6: Going to print a document
Thread 7: Going to print a document
Thread 2: Going to print a document
Thread 5: Going to print a document
Thread 3: Going to print a document
Thread 0: Going to print a document
Thread 9: PrintQueue 2 : Printing a Job during 2 seconds :: Time - Tue Jan 13 16:28:58 IST 2015
Thread 4: PrintQueue 1 : Printing a Job during 7 seconds :: Time - Tue Jan 13 16:28:58 IST 2015
Thread 1: PrintQueue 0 : Printing a Job during 1 seconds :: Time - Tue Jan 13 16:28:58 IST 2015
Thread 1: The document has been printed
Thread 8: PrintQueue 0 : Printing a Job during 1 seconds :: Time - Tue Jan 13 16:29:00 IST 2015
Thread 9: The document has been printed
Thread 6: PrintQueue 2 : Printing a Job during 0 seconds :: Time - Tue Jan 13 16:29:01 IST 2015
Thread 6: The document has been printed
Thread 7: PrintQueue 2 : Printing a Job during 4 seconds :: Time - Tue Jan 13 16:29:01 IST 2015
Thread 8: The document has been printed
Thread 2: PrintQueue 0 : Printing a Job during 5 seconds :: Time - Tue Jan 13 16:29:02 IST 2015
Thread 7: The document has been printed
Thread 5: PrintQueue 2 : Printing a Job during 8 seconds :: Time - Tue Jan 13 16:29:05 IST 2015
Thread 4: The document has been printed
Thread 3: PrintQueue 1 : Printing a Job during 4 seconds :: Time - Tue Jan 13 16:29:06 IST 2015
Thread 2: The document has been printed
Thread 0: PrintQueue 0 : Printing a Job during 4 seconds :: Time - Tue Jan 13 16:29:08 IST 2015
Thread 3: The document has been printed
Thread 0: The document has been printed
Thread 5: The document has been printed

在上面的示例中,使用3作为构造函数的参数创建信号量对象。 调用acquire()方法的前三个线程将获得对打印机的访问权限,而其余线程将被阻塞。 当一个线程完成关键部分并释放信号量时,另一个线程将获取它。

在printJob()方法中,线程获取分配用于打印此作业的打印机的索引。

这就是这个简单但重要的概念。 如果有的话,请把你的问题和评论留下。

原文链接: howtodoinjava 翻译: 随波不逐流- wavemelody
译文链接: https://www.cnblogs.com/mymelody/p/9556037.html

使用Semaphore控制对资源的多个副本的并发访问的更多相关文章

  1. 使用Semaphore控制并发访问

    Semaphore,信号量. 用在多线程环境下对共享资源访问的一种协调机制. 当一个线程想要访问共享的资源时,这个线程需要获取Semaphore,如果Semaphore内部计数器的值大于0,Semap ...

  2. Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行

    Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行 Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执 ...

  3. JUC并发工具类之Semaphore控制并发线程数

    首先看看关于Semaphore的UML图: 从上图看,信号量的实现原理与锁类似,是基于AQS的:有公平与非公平之分.当初始的资源数为1时就退化为排它锁了,资源总数即state的初始值,在acquire ...

  4. laravel控制器之资源控制器

    资源控制器 Laravel 的资源控制器可以让我们很便捷地构建基于资源的 RESTful 控制器,例如,你可能想要在应用中创建一个控制器,用于处理关于文章存储的 HTTP 请求,使用 Artisan ...

  5. Semaphore可以控制并发访问的线程个数

    public class SemaphoreTest { //信号量,只允许 3个线程同时访问 ); public static void main(String[] args) { Executor ...

  6. Java技术之如何保证同一资源被多个线程并发访问时的完整性?

    常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问.Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持. 在Java中一共有四种方法支持同步,其中前三个是同步 ...

  7. 怎样利用好单片机上的存储器资源来实现OD的存储与访问

    转自:http://www.cnblogs.com/winshton/p/4897789.html 我们知道OD(对象字典)是CANopen的核心,所有功能都是围绕它开展的,是协议栈的数据中心,良好的 ...

  8. view是视图层+action是控制层+service是业务层+dao是数据访问层。

  9. 旧文备份:怎样利用好单片机上的存储器资源来实现OD的存储与访问

    我们知道OD(对象字典)是CANopen的核心,所有功能都是围绕它开展的,是协议栈的数据中心,良好的OD实现是协议栈高效稳定运行的基础,而OD的实现最基本的一点就是怎么去保存它.因为OD的内容比较杂, ...

随机推荐

  1. 我们为什么要搞长沙.NET技术社区(三)

    我们为什么要搞长沙.NET技术社区(三) 万事先从饭局开始是中华民族留下来的一个优秀的传统美德. 昨天晚餐时间,长沙 .net 技术社区的主要发起人员进行了一番小聚,同时也作为一个非正式会议,对社区发 ...

  2. 【从零开始搭建自己的.NET Core Api框架】(三)集成轻量级ORM——SqlSugar:3.1 搭建环境

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...

  3. [Swift]LeetCode413. 等差数列划分 | Arithmetic Slices

    A sequence of number is called arithmetic if it consists of at least three elements and if the diffe ...

  4. [Swift]LeetCode638. 大礼包 | Shopping Offers

    In LeetCode Store, there are some kinds of items to sell. Each item has a price. However, there are ...

  5. redis缓存使用

    什么是缓存(cache): 在项目中没有必要每次请求都查询数据库的情况就可以使用缓存,让每次请求先查询缓存,如果命中,就直接返回缓存结果,如果没有命中,就查询数据库, 并将查询结果放入缓存,下次请求时 ...

  6. MySql综合知识汇总

    本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB Mysql驱动:com.mysql.jdbc.Driver MysqlURL:jdbc:mysql://loca ...

  7. Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制

    目录 1. Hibernate的查询方式 1.1 方式一:OID查询 1.2 方式二:对象导航查询 1.3 方式三:HQL方式 1.4 方式四:QBC查询 1.5 方式五:SQL查询 2. 环境搭建 ...

  8. 第2章 Java编程基础

    本章重点 ·Java的基本语法形式 ·Java语言中的常量与变量 ·Java语言运算符的使用 ·Java程序的流程控制 ·Java中方法的定义与使用 ·Java中数组的定义与使用 2.1 Java的基 ...

  9. SpringBoot时间戳与MySql数据库记录相差14小时排错

    项目中遇到存储的时间戳与真实时间相差14小时的现象,以下为解决步骤. 问题 CREATE TABLE `incident` ( `id` int(11) NOT NULL AUTO_INCREMENT ...

  10. Linux查找文件内容

    从当前目录递归查找文件名为 .py 中包含 conf 的文件名: find -name "*.py" | xargs grep "conf"