返回顶部
首页 > 资讯 > 精选 >JUC怎么模拟AND型信号量
  • 466
分享到

JUC怎么模拟AND型信号量

2023-06-16 17:06:40 466人浏览 薄情痞子
摘要

这篇文章主要介绍“JUC怎么模拟AND型信号量”,在日常操作中,相信很多人在JUC怎么模拟AND型信号量问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JUC怎么模拟AND型信号量”的疑惑有所帮助!接下来,请跟

这篇文章主要介绍“JUC怎么模拟AND型信号量”,在日常操作中,相信很多人在JUC怎么模拟AND型信号量问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JUC怎么模拟AND型信号量”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1.一个错误示例

在这里,首先解释一下,为了满足线程申请信号量不成功后将进程阻塞,并插入到对应的队列中,所以使用了ReentrantLock+Condition来实现Swait方法。废话不多说,直接上代码:

//数据定义  static Lock lock = new ReentrantLock();  static Condition condition1 = lock.newCondition();  static Condition condition2 = lock.newCondition();  public static void Swait(String id, Semaphore s1, Semaphore s2) throws InterruptedException {  lock.tryLock(1, TimeUnit.SECONDS);  log.info("当前的两个信号量的状态:【{},{}】", s1.availablePermits(), s2.availablePermits());  //availablePermits可获取到信号量中还剩余的值  if(s1.availablePermits() < 1 || s2.availablePermits() < 1){  if (s1.availablePermits() < 1) {  log.info("线程【{}】被挂起到信号量【{}】中", id, s1);  //阻塞,并插入到condition1的阻塞队列中  condition1.await();  } else {  log.info("线程【{}】被挂起到信号量【{}】中", id, s2);  //阻塞,并插入到condition2的阻塞队列中  condition2.await();  }  log.info("被挂起的线程【{}】被唤醒执行。", id);  } else {  log.info("为线程【{}】分配资源!", id);  s1.acquire();  s2.acquire();  }  lock.unlock();  }  public static void Ssignal(Semaphore s1, Semaphore s2) throws InterruptedException {  log.info("线程【{}】执行了释放资源", id);  lock.tryLock(1, TimeUnit.SECONDS);  s1.release();  s2.release();  //唤醒等待队列中的线程  condition.signal();  lock.unlock();  }

 大家仔细看上面的代码,这个也是我刚开始写的代码,第一眼看似乎是没什么问题,但是里面隐藏着一个坑,在Swait方法中,调用condition1.await(),此时线程被阻塞在这一行中,但是当被别的线程(调用Ssignal)唤醒时,在被阻塞的下一行开始继续执行,但是在后续的代码里,是没有去申请信号量的,而是直接就Swait成功了,这样在执行Ssignal时就会导致信号量凭空的增加了,也就无法正确的表征系统中的资源数量了。

2.一个简单的示例

 下面我们就对代码进行优化,大家可以回顾一下AND型信号量,当其因为资源不足时,需要将线程插入到第一个无法满足条件(即Si<1)的信号量对应的等待队列中,并且将程序计数器放置到Swait操作的开始处,所以我们对Swait代码进行修改如下:

public static void Swait(String id, Semaphore s1, Semaphore s2) throws InterruptedException {  lock.tryLock(1, TimeUnit.SECONDS);  log.info("当前的两个信号量的状态:【{},{}】", s1.availablePermits(), s2.availablePermits());  //如果申请不到,就挂起线程,并将线程插入到condition的队列中  while (s1.availablePermits() < 1 || s2.availablePermits() < 1) {  if (s1.availablePermits() < 1) {  log.info("线程【{}】被挂起到信号量【{}】中", id, s1);  condition1.await();  } else {  log.info("线程【{}】被挂起到信号量【{}】中", id, s2);  condition2.await();  }  log.info("被挂起的线程【{}】被唤醒执行。", id);  }  log.info("为线程【{}】分配资源!", id);  s1.acquire();  s2.acquire();  lock.unlock();  }

 在上面的代码中,我们将请求的资源放到一个循环条件中,以满足将程序计数器放置到Swait操作的开始处,在每次被唤醒后都要重新判断资源是否足够,如果足够才跳出循环,否则就再次自我阻塞。

3.一个可以同时申请N个的Swait操作

 如果你知道了信号量的种类数(系统中的资源类型),其实上面的代码已经可以满足一定的需要了,只需要我们将所有的信号量写入到参数列表中即可。但是对于致力于代码的复用,这里就有些差强人意了,因此我们再次对代码进行改进,代码如下所示:

public static void Swait(String id, Semaphore... list) throws InterruptedException {  lock.lock();  //如果资源不足,就挂起线程,并将线程插入到condition的队列中  while (true) {  int count=0;  //循环判断参数列表中信号量的可用值  for (Semaphore semaphore:list){  if(semaphore.availablePermits()>0){  count++;  }  }  //如果资源都满足,则跳出循环,进行资源分配  if(count == list.length){  break;  }  log.info("线程【{}】被挂起-----", id);  //将当前线程阻塞  condition1.await();  log.info("被挂起的线程【{}】被唤醒执行。", id);  }  log.info("为线程【{}】分配资源!", id);  //分配资源  for (Semaphore semaphore:list){  semaphore.acquire();  }  lock.unlock();  }  public static void Ssignal(String id, Semaphore... list) throws InterruptedException {  log.info("线程【{}】执行了释放资源", id);  lock.tryLock(1, TimeUnit.SECONDS);  //循环释放信号量  for (Semaphore semaphore:list){  semaphore.release();  }  //唤醒等待队列中的线程  condition.signal();  lock.unlock();  }

 为此,我们将方法中的信号量列表改为可变的参数列表,这样在传参的时候就可以方便的进行了,但是也会存才一些问题,比如无法约束“借出”与“归还”的信号量的数量是否一致。并且因为信号量的数量不定,所以无法为每个信号量新建一个条件变量(Condition),因此在上面的代码中所有的信号量公用一个条件变量,所有阻塞的线程都插入在其阻塞队列中。

4.一个完整的例子

这里我们使用一个经典的进程同步问题来演示我们使用Java模拟的AND型信号量,在这里,我们采用生产者&ndash;消费者问题来演示,完整的代码如下:

//用来保证互斥的访问临界区(缓存区)  static final Semaphore mutex = new Semaphore(1);  //缓冲区,最大容量为50  static List<Integer> buffer = new ArrayList<>();  //缓冲区中还可放入的消息数量  static final Semaphore empty = new Semaphore(50);  //缓冲区中的消息数量  static final Semaphore full = new Semaphore(0);  //可重入和条件变量  static Lock lock = new ReentrantLock();  static Condition condition = lock.newCondition();  //用与辅助的简单的生成消息  static Integer count = 0;  //生产者  static class Producer extends Thread {  Producer(String name) {  super.setName(name);  }  @Override  public void run() {  do {  try {  Swait(this.getName(), mutex, empty);  log.info("生产了一条消息:【{}】", count);  buffer.add(count++);  Thread.sleep(1000);  Ssignal(this.getName(), mutex, full);  } catch (InterruptedException e) {  log.error("生产消息时产生异常!");  }  } while (true);  }  }  //消费者  static class Consumer extends Thread {  Consumer(String name) {  super.setName(name);  }  @Override  public void run() {  do {  try {  Swait(this.getName(), mutex, full);  log.info("消费了一条消息:【{}】", buffer.remove(0));  Thread.sleep(1000);  Ssignal(this.getName(), mutex, empty);  } catch (InterruptedException e) {  log.error("消费消息时产生异常!");  }  } while (true);  }  }  public static void Swait(String id, Semaphore... list) throws InterruptedException {  lock.lock();  //如果资源不足,就挂起线程,并将线程插入到condition的队列中  while (true) {  int count=0;  for (Semaphore semaphore:list){  if(semaphore.availablePermits()>0){  count++;  }  }  if(count == list.length){  break;  }  log.info("线程【{}】被挂起", id);  condition.await();  log.info("被挂起的线程【{}】被唤醒执行。", id);  }  log.info("为线程【{}】分配资源!", id);  for (Semaphore semaphore:list){  semaphore.acquire();  }  lock.unlock();  }  public static void Ssignal(String id, Semaphore... list) throws InterruptedException {  log.info("线程【{}】执行了释放资源", id);  lock.tryLock(1, TimeUnit.SECONDS);  for (Semaphore semaphore:list){  semaphore.release();  }  //唤醒等待队列中的一个线程  condition.signal();  lock.unlock();  }  public static void main(String[] args) {  Producer p1 = new Producer("p1");  Consumer c1 = new Consumer("c1");  p1.start();  c1.start();  }

上面代码都是可以直接执行的,如果不需要使用参数列表,可以将上面的Swait方法进行替换即可(记得创建对应的条件变量)。


到此,关于“JUC怎么模拟AND型信号量”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: JUC怎么模拟AND型信号量

本文链接: https://lsjlt.com/news/284552.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JUC怎么模拟AND型信号量
    这篇文章主要介绍“JUC怎么模拟AND型信号量”,在日常操作中,相信很多人在JUC怎么模拟AND型信号量问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JUC怎么模拟AND型信号量”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-16
  • Java中信号量模型的实际应用
    本篇内容介绍了“Java中信号量模型的实际应用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java信号量模型的工作方式如下:线程在运行的过...
    99+
    2023-06-17
  • 怎么理解python信号量
    本篇内容介绍了“怎么理解python信号量”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!01:信号量1)概述:信号量是用来控制线程并发数的。...
    99+
    2023-06-01
  • swoole中信号量怎么使用
    这篇文章主要介绍了swoole中信号量怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇swoole中信号量怎么使用文章都会有所收获,下面我们一起来看看吧。在swoole中,信号量主要用来保护共享资源,使得...
    99+
    2023-06-29
  • FreeRTOS信号量API函数怎么用
    这篇文章主要介绍“FreeRTOS信号量API函数怎么用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“FreeRTOS信号量API函数怎么用”文章能帮助大家解决问题。    &n...
    99+
    2023-06-29
  • r语言怎么拟合ARIMA模型
    在R语言中,可以使用arima()函数来拟合ARIMA模型,具体步骤如下: 首先安装并加载forecast包,因为arima()函...
    99+
    2024-03-04
    r语言
  • Java中怎么实现线程间通信与信号量
    Java中怎么实现线程间通信与信号量,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.信号量Semaphore先说说Semaphore,Semaphore可以控制某个资源可...
    99+
    2023-05-30
    java
  • c#模拟串口通信SerialPort怎么实现
    这篇“c#模拟串口通信SerialPort怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“c#模拟串口通信Serial...
    99+
    2023-06-30
  • python怎么模拟taobao搜索商品信息
    今天就跟大家聊聊有关python怎么模拟taobao搜索商品信息,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。相信大家都在淘宝上买到东西吧,淘宝上会有一个对应的淘宝搜索框,让你搜索对...
    99+
    2023-06-02
  • Chainer怎么支持模型量化和轻量化
    Chainer并不直接支持模型量化和轻量化,但可以通过一些方法来实现。 使用深度学习框架的转换工具:可以先使用Chainer训练...
    99+
    2024-04-02
  • CNTK怎么支持模型量化和轻量化
    CNTK(Microsoft Cognitive Toolkit)支持模型量化和轻量化的方法包括以下几种: 使用量化模型训练技术...
    99+
    2024-04-02
  • Caffe怎么处理模型过拟合问题
    添加正则化项:通过在损失函数中添加正则化项,可以限制模型的复杂度,防止过拟合。常用的正则化方法包括L1正则化和L2正则化。 ...
    99+
    2024-03-07
    Caffe
  • PyTorch中怎么进行模型的量化
    在PyTorch中,可以使用torch.quantization模块来进行模型的量化。具体步骤如下: 定义模型并加载预训练的模型参...
    99+
    2024-03-05
    PyTorch
  • 云服务器怎么用模拟器登录账号
    如果您想使用云服务器登录模拟器账号,您需要先安装一个模拟器,可以在网上搜索“云服务器模拟器”等关键词,按照步骤操作一下,一般都可以轻松地登录模拟器。以下是云服务器模拟器的使用方法: 安装模拟器:在您的计算机上安装相应的模拟器,例如 St...
    99+
    2023-10-26
    模拟器 账号 服务器
  • 怎么快速查看电脑主板型号信息
    这篇文章主要讲解了“怎么快速查看电脑主板型号信息”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么快速查看电脑主板型号信息”吧!快速查看电脑主板型号信息的步骤第一种方法 首先打开命令运行窗,...
    99+
    2023-07-01
  • pytorch怎么获得模型的计算量和参数量
    这篇文章给大家分享的是有关pytorch怎么获得模型的计算量和参数量的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。方法1 自带pytorch自带方法,计算模型参数总量total = sum([...
    99+
    2023-06-15
  • 使用Unity怎么批量修改FBX模型
    本篇文章给大家分享的是有关使用Unity怎么批量修改FBX模型,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。using UnityEditor;using ...
    99+
    2023-06-14
  • java中怎么模拟和使用全局变量
    在Java中,没有全局变量的概念。但是可以通过以下几种方式来模拟和使用全局变量:1. 使用静态变量:将需要模拟的全局变量定义为一个静...
    99+
    2023-09-15
    java
  • 怎么看待Linux 多线程中的信号量Semaphore
    今天就跟大家聊聊有关怎么看待Linux 多线程中的信号量Semaphore,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。理解 Semaphore,从一个好的翻译开始Semaphore...
    99+
    2023-06-15
  • 云服务器怎么用模拟器登录账号啊
    如果您想使用云服务器进行登录,可以按照以下步骤进行操作: 打开云平台,登录云服务器的账户。 输入云服务器登录凭证(也称为密钥),例如https://cloud.cloudserve.com/your_username.html。 点击“...
    99+
    2023-10-27
    模拟器 账号 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作