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. [SQL]LeetCode596. 超过5名学生的课 | Classes More Than 5 Students

    SQL架构 Create table If Not Exists courses (student varchar(), )) Truncate table courses insert into c ...

  2. [Swift]LeetCode844. 比较含退格的字符串 | Backspace String Compare

    Given two strings S and T, return if they are equal when both are typed into empty text editors. # m ...

  3. [Swift]LeetCode996. 正方形数组的数目 | Number of Squareful Arrays

    Given an array A of non-negative integers, the array is squareful if for every pair of adjacent elem ...

  4. Redis Windows下安装方法

    一.安装 首先在网上下载Redis,下载地址:https://github.com/MicrosoftArchive/redis/releases 根据电脑系统的实际情况选择32位还是64位,在这里我 ...

  5. 【译】如何高效的使用 Git

    原文链接 代码昨天还是运行好好的今天就不行了. 代码被删了. 突然出现了一个奇怪的 bug,但是没人知道怎么回事. 如果你出现过上面的任何一种情况,那本篇文章就是为你准备的. 除了知道 git add ...

  6. 如何在.NET Core控制台程序中使用依赖注入

    背景介绍 依赖注入(Dependency Injection), 是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度.在.NET Core MVC中 我们可以在Startup.cs文件的Co ...

  7. 代理自动配置文件PAC的使用方法

    我通常上网使用两个浏览器,safari用于一般上网:Chrome安装SwitchyOmega插件,在不同的代理中切换,来保证某些网站的上网速度. 但是这种方式到了手机上就有点懵,几乎所有的iPhone ...

  8. Asp.Net Core中利用Seq组件展示结构化日志功能

    在一次.Net Core小项目的开发中,掌握的不够深入,对日志记录并没有好好利用,以至于一出现异常问题,都得跑动服务器上查看,那时一度怀疑自己肯定没学好,不然这一块日志不可能需要自己扒服务器日志来查看 ...

  9. MySQL的可重复读级别能解决幻读吗

    引言 之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了.但是对于幻 ...

  10. 前端笔记之HTML5&CSS3(上)新特性&音频视频&本地存储&自定义属性

    一.HTML5简介 HTML 5 的第一份正式草案已于2008年1月22日公布.HTML5 仍处于完善之中.然而,大部分现代浏览器已经具备了某些 HTML5 支持. 2014年10月29日,万维网联盟 ...