1.symaPhore简介

symaphore(信号量)用来控制同时访问某个资源的线程数量,一般用在并发流量控制。个人对它的理解相当于是接待室每次只能接待固定数量的人,当达到最高接待数的时候,其他人就会被拦截在外等待,当前面接待完走出接待室,才会继续接待下面的人。

2.symaphore使用

symaphore有两个构造方法:构造方法Semaphore(int permits)接受一个int参数,表示可用的许可证数量,内部默认创建一个非公平锁;构造方法Semaphore(int permits, boolean fair)接受一个

int和一个boolean值,分别表示可用许可证数量和是否使用公平锁。(公平锁和非公平锁后面文章会单独提到)

一般在做流量控制的时候,我们就可以通过控制许可证数量来控制并发数的大小,接下来具体聊聊怎么实现对线程池的控制,代码如下:

 1 public class DBPoolSemaphore {
2
3 private final static int POOL_SIZE = 10;
4 private final Semaphore useful,useless;//useful表示可用的数据库连接,useless表示已用的数据库连接
5
6 public DBPoolSemaphore() {
7 this. useful = new Semaphore(POOL_SIZE);
8 this.useless = new Semaphore(0);
9 }
10
11 //存放数据库连接的容器
12 private static LinkedList<Connection> pool = new LinkedList<Connection>();
13 //初始化池
14 static {
15 for (int i = 0; i < POOL_SIZE; i++) {
16 pool.addLast(SqlConnectImpl.fetchConnection());
17 }
18 }
19
20 /*归还连接*/
21 public void returnConnect(Connection connection) throws InterruptedException {
22 if(connection!=null) {
23 System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
24 +"可用连接数:"+useful.availablePermits());
25 useless.acquire();
26 synchronized (pool) {
27 pool.addLast(connection);
28 }
29 useful.release();
30 }
31 }
32
33 /*从池子拿连接*/
34 public Connection takeConnect() throws InterruptedException {
35 useful.acquire();
36 Connection conn;
37 synchronized (pool) {
38 conn = pool.removeFirst();
39 }
40 useless.release();
41 return conn;
42 }
43 }

首先创建了两个symaphore对象,分别用来表示已用线程池和可用线程池,在设计拿连接和归还连接时,分别先后调用acquire()和release(),acquire()是用来获取许可,release()归还许可,相当于在拿连接时先去可用连接池获取许可,获取到才会继续执行,否则阻塞等待,直到有连接池归还了连接,可用线程许可中可以获取到,获取数据库连接,之后将不可用连接许可增加;归还连接刚好相反。本质就是通过控制可用和不可用许可数目,达到控制并发流量的效果。

下面是我设计的一段执行上面代码的示例:

 1 public class AppTest {
2
3 private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
4
5 //业务线程
6 private static class BusiThread extends Thread{
7 @Override
8 public void run() {
9 Random r = new Random();//让每个线程持有连接的时间不一样
10 long start = System.currentTimeMillis();
11 try {
12 Connection connect = dbPool.takeConnect();
13 System.out.println("Thread_"+Thread.currentThread().getId()
14 +"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
15 SleepTools.ms(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
16 System.out.println("查询数据完成,归还连接!");
17 dbPool.returnConnect(connect);
18 } catch (InterruptedException e) {
19 }
20 }
21 }
22
23 public static void main(String[] args) {
24 for (int i = 0; i < 50; i++) {
25 Thread thread = new BusiThread();
26 thread.start();
27 }
28 }
29
30 }

有兴趣的同学可以使用上述代码跑一下,可以看到前10个线程不耗时间,可以直接获取到,后面的会阻塞(花费时间越来越长),归还一个才会去获取连接,因为我的连接许可设置为10,所以每次最高并发数为10。

其他方法

Semaphore还提供一些其他方法:

  • int availablePermits() :返回此信号量中当前可用的许可证数。
  • int getQueueLength():返回正在等待获取许可证的线程数。
  • boolean hasQueuedThreads() :是否有线程正在等待获取许可证。
  • void reducePermits(int reduction) :减少reduction个许可证。是个protected方法。
  • Collection getQueuedThreads() :返回所有等待获取许可证的线程集合。是个protected方法。

ps:部分引用自http://ifeve.com/concurrency-semaphore/

并发编程常用工具类(二) SymaPhore实现线程池的更多相关文章

  1. 并发编程常用工具类(一) countDownLatch和cyclicBarrier的使用对比

    1.CountDownLatch           countDownLatch的作用是让一组线程等待其他线程完成工作以后在执行,相当于加强版的join(不懂可以百度一下join的用法),一般在初始 ...

  2. java并发编程 - Exexctors 工具类

    Executors 类提供了一系列静态工厂方法用于创建各种线程池. newFixedThreadPool 创建固定大小的线程池.每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小.线程池的大 ...

  3. Java并发编程原理与实战二十:线程安全性问题简单总结

    一.出现线程安全性问题的条件 •在多线程的环境下 •必须有共享资源 •对共享资源进行非原子性操作   二.解决线程安全性问题的途径 •synchronized (偏向锁,轻量级锁,重量级锁) •vol ...

  4. Java并发编程原理与实战二十一:线程通信wait&notify&join

    wait和notify wait和notify可以实现线程之间的通信,当一个线程执行不满足条件时可以调用wait方法将线程置为等待状态,当另一个线程执行到等待线程可以执行的条件时,调用notify可以 ...

  5. java并发编程(十七)Executor框架和线程池

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497   Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...

  6. Java并发编程实践读书笔记(5) 线程池的使用

    Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...

  7. Java并发编程原理与实战三十七:线程池的原理与使用

    一.简介 线程池在我们的高并发环境下,实际应用是非常多的!!适用频率非常高! 有过使用过Executors框架的朋友,可能不太知道底层的实现,这里就是讲Executors是由ThreadPoolExe ...

  8. Java并发编程的艺术笔记(八)——线程池

    一.线程池的主要处理流程 ThreadPoolExecutor执行execute方法分下面4种情况. 1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获 ...

  9. 三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解

    01-并发编程之Executor线程池详解 线程:什么是线程&多线程 线程:线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...

随机推荐

  1. 推荐一款最强Python自动化神器!再也不用写代码了!

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 搞过自动化测试的小伙伴,相信都知道,在Web自动化测试中,有一款自动化测试神器工具: seleniu ...

  2. Python 带你高效创作短视频,视频创作秀到飞起!!!

    近两年,抖音.快手将短视频推到风口浪尖上,要生产出高质量的视频,离不开视频剪辑这一环节:在全民剪片浪潮中,大众使用最多的剪辑软件如:Pr.FCPX.剪印.Vue 等. 视频剪辑过程中,Python 一 ...

  3. net core 3.1使用ElasticSearch 全文搜索引擎

    ElasticSearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene 基础之上. Lucene 可以说是当下最先进.高性能.全功能的搜索引擎库,无论是开源还是私有. ...

  4. C# 托管与非托管类型 堆和栈 值类型与引用类型 装箱与拆箱

    一.托管类型与非托管类型 1.托管类型 托管类型包括 引用类型 以及 包含有引用类型或托管类型成员的结构. 引用类型 含引用类型或托管类型成员(字段.自动实现 get 访问器的属性)的结构 // 托管 ...

  5. C#WebApi 接口增加备注和测试 默认api文档

    1:配置 接口注释. (1)配置生成xml的路径.我们在项目上面点右键→属性→生成标签页配置xml的路径. (2)在xml的读取路径:在Areas\HelpPage\App_Start\HelpPag ...

  6. 点名小辣辣,带你入门 JMeter (。・∀・)ノ゙

    什么是 JMeter Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测 试但后来扩展到其他测试领域. 它可以用于测试静态 ...

  7. Oracel 修改字段类型(有数据的情况)

    1 /*修改原字段名bh为bh_tmp*/ 2 alter table Tab_Name rename column bh to bh_tmp; 3 /*增加一个和原字段名同名的字段bh*/ 4 al ...

  8. LeapMotion控制器 java语言开发笔记--(连接控制器)

    (1)为了连接LeapMotion控制器,创建controller对象,这个对象自动创建与控制器的服务或者后台程序连接,然后捕获数据提供给你的应用程序.可以使用该对象来获取连接信息. (2)获取Fra ...

  9. ES6箭头函数与this指向

    一.ES6箭头函数 ES6之前的语法想要定义一个函数,如图example1,ES6之后定义一个函数如图example2,相比较之下简洁了很多 二.函数的this指向 非箭头函数,谁调用函数this指向 ...

  10. 「译」Blazor VS React React / Angular / Vue.js

    原文作者: Christian Findlay 原文链接: https://christianfindlay.com/2020/06/04/blazor-vs-react-angular-vue-js ...