并发编程常用工具类(二) SymaPhore实现线程池
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实现线程池的更多相关文章
- 并发编程常用工具类(一) countDownLatch和cyclicBarrier的使用对比
1.CountDownLatch countDownLatch的作用是让一组线程等待其他线程完成工作以后在执行,相当于加强版的join(不懂可以百度一下join的用法),一般在初始 ...
- java并发编程 - Exexctors 工具类
Executors 类提供了一系列静态工厂方法用于创建各种线程池. newFixedThreadPool 创建固定大小的线程池.每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小.线程池的大 ...
- Java并发编程原理与实战二十:线程安全性问题简单总结
一.出现线程安全性问题的条件 •在多线程的环境下 •必须有共享资源 •对共享资源进行非原子性操作 二.解决线程安全性问题的途径 •synchronized (偏向锁,轻量级锁,重量级锁) •vol ...
- Java并发编程原理与实战二十一:线程通信wait¬ify&join
wait和notify wait和notify可以实现线程之间的通信,当一个线程执行不满足条件时可以调用wait方法将线程置为等待状态,当另一个线程执行到等待线程可以执行的条件时,调用notify可以 ...
- java并发编程(十七)Executor框架和线程池
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...
- Java并发编程实践读书笔记(5) 线程池的使用
Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...
- Java并发编程原理与实战三十七:线程池的原理与使用
一.简介 线程池在我们的高并发环境下,实际应用是非常多的!!适用频率非常高! 有过使用过Executors框架的朋友,可能不太知道底层的实现,这里就是讲Executors是由ThreadPoolExe ...
- Java并发编程的艺术笔记(八)——线程池
一.线程池的主要处理流程 ThreadPoolExecutor执行execute方法分下面4种情况. 1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获 ...
- 三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解
01-并发编程之Executor线程池详解 线程:什么是线程&多线程 线程:线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...
随机推荐
- eclipse 创建自己的Maven项目(超详细)
本文章 主要是 讲解 是讲解 eclipse创建项目 --SpiritMark_liu 先配置 Maven 的 settings 地址 (Window -> Perferences–>Ma ...
- SpringBoot从入门到精通教程(五)
上节,我们讲了 SpringBoot 如何使用MyBatis 今天我们讲讲 Springboot Logo自定义的问题, 我们在启动 SpringBoot 时,控制台会打印 SpringBoot Lo ...
- 这可能是目前最轻量级、最支持MVVM、可定制性最高的开源Chart控件!
由于项目中经常用到Series Chart,而目前市面又实在找不到既支持MVVM,又轻量级的开源Chart控件,于是干脆就花了两周时间随手写了一个.昨天感觉还比较满意,就发布到了Github上:htt ...
- JavaScript 正则匹配中文,中文符号,空格,全数字,以https:// 开头的url,用于各种场景的输入校验
业务场景1: 密码输入框需要验证输入中文,中文符号,空格等情况,以便于给出错误提示 业务场景2: 输入框只允许输入数字的情况 业务场景3: 输入框允许输入均为数字或以https:// 开头的url的情 ...
- npm 各种常用命令
全局删除 node-gyp npm -g uninstall node-gyp 再次安装依赖 npm install 更改包内容后重建 npm rebuild 清除缓存 npm cache clean ...
- 一道java算法题
12个人围成一圈,序号依次从1至12,从序号1开始顺时针依次数,数到7的人退出,下一个再依次从1开始数,求留下来的最后一个人的原始序号. public static void joseph(int[] ...
- [leetcode] Add to List 74. Search a 2D Matrix
/** * Created by lvhao on 2017/8/1. * Write an efficient algorithm that searches for a value in an m ...
- Arduino IDE开发ESP8266-01S连接MQTT服务器 控制继电器点亮LED
准备条件: 1.Arduino IDE 2.ESP-01S模块 2.MQTT服务器 3.手机热点或路由器热点 Wi-Fi芯片 默认订阅的主题是 "开关控制" 当你发送主题 &q ...
- docker容器中布置静态网站
docker容器中布置静态网站(基于云服务器ubuntu系统) 服务器准备(ubuntu) docker nginx 静态网页制作 浏览器测试 服务器布置 这里推荐使用云服务器(阿里云.华为云.腾讯云 ...
- Kubernetes官方java客户端之四:内部应用
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...