我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java并发编程中Semaphore计数信号量的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java并发编程中Semaphore计数信号量的示例分析

这篇文章主要为大家展示了“Java并发编程中Semaphore计数信号量的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程中Semaphore计数信号量的示例分析”这篇文章吧。

Semaphore 是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量)。

简单示例:

package me.socketthread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class SemaphoreLearn {   //信号量总数   private static final int SEM_MAX = 12;   public static void main(String[] args) {      Semaphore sem = new Semaphore(SEM_MAX);     //创建线程池     ExecutorService threadPool = Executors.newFixedThreadPool(3);     //在线程池中执行任务     threadPool.execute(new MyThread(sem, 7));     threadPool.execute(new MyThread(sem, 4));     threadPool.execute(new MyThread(sem, 2));     //关闭池     threadPool.shutdown();   } }   class MyThread extends Thread {     private volatile Semaphore sem;  // 信号量     private int count;    // 申请信号量的大小           MyThread(Semaphore sem, int count) {       this.sem = sem;       this.count = count;     }     public void run() {       try {        // 从信号量中获取count个许可         sem.acquire(count);         Thread.sleep(2000);         System.out.println(Thread.currentThread().getName() + " acquire count="+count);       } catch (InterruptedException e) {         e.printStackTrace();       } finally {         // 释放给定数目的许可,将其返回到信号量。         sem.release(count);         System.out.println(Thread.currentThread().getName() + " release " + count + "");       }     }   }

执行结果:

pool-1-thread-2 acquire count=4pool-1-thread-1 acquire count=7pool-1-thread-1 release 7pool-1-thread-2 release 4pool-1-thread-3 acquire count=2pool-1-thread-3 release 2

线程1和线程2会并发执行,因为两者的信号量和没有超过总信号量,当前两个线程释放掉信号量之后线程3才能继续执行。

源码分析:

1、构造函数

在构造函数中会初始化信号量值,这值最终是作为锁标志位state的值

Semaphore sem = new Semaphore(12);//简单来说就是给锁标识位state赋值为12

2、Semaphore.acquire(n);简单理解为获取锁资源,如果获取不到线程阻塞

Semaphore.acquire(n);//从锁标识位state中获取n个信号量,简单来说是state = state-n 此时state大于0表示可以获取信号量,如果小于0则将线程阻塞
public void acquire(int permits) throws InterruptedException {     if (permits < 0) throw new IllegalArgumentException();     //获取锁     sync.acquireSharedInterruptibly(permits);   }

acquireSharedInterruptibly中的操作是获取锁资源,如果可以获取则将state= state-permits,否则将线程阻塞

public final void acquireSharedInterruptibly(int arg)       throws InterruptedException {     if (Thread.interrupted())       throw new InterruptedException();     if (tryAcquireShared(arg) < 0)//tryAcquireShared中尝试获取锁资源       doAcquireSharedInterruptibly(arg); //将线程阻塞   }

tryAcquireShared中的操作是尝试获取信号量值,简单来说就是state=state-acquires ,如果此时小于0则返回负值,否则返回大于新值,再判断是否将当线程线程阻塞

protected int tryAcquireShared(int acquires) {       for (;;) {         if (hasQueuedPredecessors())           return -1;       //获取state值         int available = getState();       //从state中获取信号量         int remaining = available - acquires;         if (remaining < 0 ||           compareAndSetState(available, remaining))         //如果信号量小于0则直接返回,表示无法获取信号量,否则将state值修改为新值           return remaining;       }     }

doAcquireSharedInterruptibly中的操作简单来说是将当前线程添加到FIFO队列中并将当前线程阻塞。

/会将线程添加到FIFO队列中,并阻塞  private void doAcquireSharedInterruptibly(int arg)      throws InterruptedException {      //将线程添加到FIFO队列中      final Node node = addWaiter(Node.SHARED);      boolean failed = true;      try {        for (;;) {          final Node p = node.predecessor();          if (p == head) {            int r = tryAcquireShared(arg);            if (r >= 0) {              setHeadAndPropagate(node, r);              p.next = null; // help GC              failed = false;              return;            }          }          //parkAndCheckInterrupt完成线程的阻塞操作          if (shouldParkAfterFailedAcquire(p, node) &&            parkAndCheckInterrupt())            throw new InterruptedException();        }      } finally {        if (failed)          cancelAcquire(node);      }    }

3、Semaphore.release(int permits),这个函数的实现操作是将state = state+permits并唤起处于FIFO队列中的阻塞线程。

public void release(int permits) {     if (permits < 0) throw new IllegalArgumentException();   //state = state+permits,并将FIFO队列中的阻塞线程唤起     sync.releaseShared(permits);   }

releaseShared中的操作是将state = state+permits,并将FIFO队列中的阻塞线程唤起。

public final boolean releaseShared(int arg) {     //tryReleaseShared将state设置为state = state+arg     if (tryReleaseShared(arg)) {       //唤起FIFO队列中的阻塞线程       doReleaseShared();       return true;     }     return false;   }

tryReleaseShared将state设置为state = state+arg

protected final boolean tryReleaseShared(int releases) {       for (;;) {         int current = getState();         int next = current + releases;         if (next < current) // overflow           throw new Error("Maximum permit count exceeded");         //将state值设置为state=state+releases         if (compareAndSetState(current, next))           return true;       }     }

doReleaseShared()唤起FIFO队列中的阻塞线程

private void doReleaseShared() {        for (;;) {        Node h = head;        if (h != null && h != tail) {          int ws = h.waitStatus;          if (ws == Node.SIGNAL) {            if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))              continue;      // loop to recheck cases            //完成阻塞线程的唤起操作            unparkSuccessor(h);          }          else if (ws == 0 &&               !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))            continue;        // loop on failed CAS        }        if (h == head)          // loop if head changed          break;      }    }

总结:Semaphore简单来说设置了一个信号量池state,当线程执行时会从state中获取值,如果可以获取则线程执行,并且在执行后将获取的资源返回到信号量池中,并唤起其他阻塞线程;如果信号量池中的资源无法满足某个线程的需求则将此线程阻塞。

Semaphore源码:

public class Semaphore implements java.io.Serializable {   private static final long serialVersionUID = -3222578661600680210L;   private final Sync sync;   abstract static class Sync extends AbstractQueuedSynchronizer {     private static final long serialVersionUID = 1192457210091910933L;     //设置锁标识位state的初始值     Sync(int permits) {       setState(permits);     }     //获取锁标识位state的值,如果state值大于其需要的值则表示锁可以获取     final int getPermits() {       return getState();     }     //获取state值减去acquires后的值,如果大于等于0则表示锁可以获取     final int nonfairTryAcquireShared(int acquires) {       for (;;) {         int available = getState();         int remaining = available - acquires;         if (remaining < 0 ||           compareAndSetState(available, remaining))           return remaining;       }     }     //释放锁     protected final boolean tryReleaseShared(int releases) {       for (;;) {         int current = getState();         //将state值加上release值         int next = current + releases;         if (next < current) // overflow           throw new Error("Maximum permit count exceeded");         if (compareAndSetState(current, next))           return true;       }     }     //将state的值减去reductions     final void reducePermits(int reductions) {       for (;;) {         int current = getState();         int next = current - reductions;         if (next > current) // underflow           throw new Error("Permit count underflow");         if (compareAndSetState(current, next))           return;       }     }     final int drainPermits() {       for (;;) {         int current = getState();         if (current == 0 || compareAndSetState(current, 0))           return current;       }     }   }   //非公平锁   static final class NonfairSync extends Sync {     private static final long serialVersionUID = -2694183684443567898L;     NonfairSync(int permits) {       super(permits);     }     protected int tryAcquireShared(int acquires) {       return nonfairTryAcquireShared(acquires);     }   }   //公平锁   static final class FairSync extends Sync {     private static final long serialVersionUID = 2014338818796000944L;     FairSync(int permits) {       super(permits);     }     protected int tryAcquireShared(int acquires) {       for (;;) {         if (hasQueuedPredecessors())           return -1;         int available = getState();         int remaining = available - acquires;         if (remaining < 0 ||           compareAndSetState(available, remaining))           return remaining;       }     }   }   //设置信号量   public Semaphore(int permits) {     sync = new NonfairSync(permits);   }   public Semaphore(int permits, boolean fair) {     sync = fair ? new FairSync(permits) : new NonfairSync(permits);   }   //获取锁   public void acquire() throws InterruptedException {     sync.acquireSharedInterruptibly(1);   }   public void acquireUninterruptibly() {     sync.acquireShared(1);   }   public boolean tryAcquire() {     return sync.nonfairTryAcquireShared(1) >= 0;   }   public boolean tryAcquire(long timeout, TimeUnit unit)     throws InterruptedException {     return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));   }   public void release() {     sync.releaseShared(1);   }   //获取permits值锁   public void acquire(int permits) throws InterruptedException {     if (permits < 0) throw new IllegalArgumentException();     sync.acquireSharedInterruptibly(permits);   }   public void acquireUninterruptibly(int permits) {     if (permits < 0) throw new IllegalArgumentException();     sync.acquireShared(permits);   }   public boolean tryAcquire(int permits) {     if (permits < 0) throw new IllegalArgumentException();     return sync.nonfairTryAcquireShared(permits) >= 0;   }   public boolean tryAcquire(int permits, long timeout, TimeUnit unit)     throws InterruptedException {     if (permits < 0) throw new IllegalArgumentException();     return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));   }   //释放   public void release(int permits) {     if (permits < 0) throw new IllegalArgumentException();     sync.releaseShared(permits);   }   public int availablePermits() {     return sync.getPermits();   }   public int drainPermits() {     return sync.drainPermits();   }   protected void reducePermits(int reduction) {     if (reduction < 0) throw new IllegalArgumentException();     sync.reducePermits(reduction);   }   public boolean isFair() {     return sync instanceof FairSync;   }   public final boolean hasQueuedThreads() {     return sync.hasQueuedThreads();   }   public final int getQueueLength() {     return sync.getQueueLength();   }   protected Collection<Thread> getQueuedThreads() {     return sync.getQueuedThreads();   }   public String toString() {     return super.toString() + "[Permits = " + sync.getPermits() + "]";   } }

以上是“Java并发编程中Semaphore计数信号量的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java并发编程中Semaphore计数信号量的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java并发编程中Semaphore计数信号量的示例分析

这篇文章主要为大家展示了“Java并发编程中Semaphore计数信号量的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程中Semaphore计数信号量的示例分析”这篇文章
2023-05-31

Java并发编程实战:信号量Semaphore的使用技巧与示例

信号量作为实战多线程编程的得力助手,通过合理的使用,可以有效地解决资源访问的问题,提高程序的并发性能。然而,信号量的使用并非易事,需要深入理解其运作原理和应用场景,才能在实际开发中灵活运用。

Java并发编程之Semaphore(信号量)详解及实例

Java并发编程之Semaphore(信号量)详解及实例概述通常情况下,可能有多个线程同时访问数目很少的资源,如客户端建立了若干个线程同时访问同一数据库,这势必会造成服务端资源被耗尽的地步,那么怎样能够有效的来控制不可预知的接入量呢?及在同
2023-05-31

Java并发编程之线程池的示例分析

这篇文章将为大家详细讲解有关Java并发编程之线程池的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是线程池是一种基于池化思想管理线程的工具。池化技术:池化技术简单点来说,就是提前保存大量的资
2023-06-20

Java面试题之并发编程的示例分析

小编给大家分享一下Java面试题之并发编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!面试题1:说一下你对ReentrantLock的理解?ReentrantLock是JDK1.5引入的,它拥有与synchro
2023-06-20

Java并发编程之ConcurrentLinkedQueue源码的示例分析

这篇文章给大家分享的是有关Java并发编程之ConcurrentLinkedQueue源码的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、ConcurrentLinkedQueue介绍并编程中,一般需
2023-06-15

Shell编程中变量数值计算的示例分析

小编给大家分享一下Shell编程中变量数值计算的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!如果要执行运算,那就少不了运算符,和其他的编程语言相似,shell也有很多的运算符如下:+、-、:代表着加号 和减号 或
2023-06-09

java中volatile变量并发操作的示例分析

小编给大家分享一下java中volatile变量并发操作的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java的特点有哪些Java的特点有哪些1.Jav
2023-06-14

Java并发编程之Fork/Join框架的示例分析

这篇文章主要介绍了Java并发编程之Fork/Join框架的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、Fork/Join框架的理解ForkJoinTask类属
2023-06-15

Java并发编程之关键字volatile的示例分析

这篇文章给大家分享的是有关Java并发编程之关键字volatile的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、作用被 volatile 修饰的变量1.保证了不同线程对该变量操作的内存可见性2.禁止
2023-06-15

Java中多线程与并发的示例分析

这篇文章主要介绍Java中多线程与并发的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、进程与线程进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。线程:是进程的一个执行路径,一个
2023-06-15

Java并发中守护线程的示例分析

今天就跟大家聊聊有关Java并发中守护线程的示例分析,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemo
2023-06-17

JUC并发编程中进程与线程的示例分析

这篇文章将为大家详细讲解有关JUC并发编程中进程与线程的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,
2023-06-29

Java并发编程之同步容器与并发容器的示例分析

这篇文章主要为大家展示了“Java并发编程之同步容器与并发容器的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java并发编程之同步容器与并发容器的示例分析”这篇文章吧。一、同步容器 1
2023-06-15

编程语言之高并发系统中限流的示例分析

这篇文章主要介绍了编程语言之高并发系统中限流的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。本文结合作者的
2023-05-30

Linux中Shell多进程并发以及并发数控制的示例分析

这篇文章主要介绍了Linux中Shell多进程并发以及并发数控制的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 基础知识准备1.1. linux后台进程Unix
2023-06-10

java并发编程工具类JUC之LinkedBlockingQueue链表队列的示例分析

小编给大家分享一下java并发编程工具类JUC之LinkedBlockingQueue链表队列的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!java.u
2023-06-15

微信小程序开发中变量值共用的示例分析

这篇文章将为大家详细讲解有关微信小程序开发中变量值共用的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。  7月16日开始,阿里巴巴国际站将实施重复铺货处罚新规。对于重复铺货商品占“审核通过且已上架
2023-06-26

微信小程序开发中数据传递和存储的示例分析

这篇文章主要介绍微信小程序开发中数据传递和存储的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1.短生命周期数据存储以小程序启动到彻底关闭为周期的的数据建议存储在app.js文件夹中,引用app.js:con
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录