并发编程常用工具类(二) 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 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...
随机推荐
- 快速理解Python异步编程的基本原理
第一个例子 假设你需要用电饭煲煮饭,用洗衣机洗衣服,给朋友打电话让他过来吃饭.其中,电饭煲需要30分钟才能把饭煮好,洗衣机需要40分钟才能把衣服洗好,朋友需要50分钟才能到你家.那么,是不是你需要在这 ...
- 【Tomcat】Tomcat原理与系统架构
目录 版本: 一,目录说明 二,浏览器访问服务器的流程 三,Tomcat系统总体架构 3.1 Tomcat请求的大致流程 3.2 Servlet容器处理请求流程 3.3 Tomcat系统总体架构 四, ...
- 从零开始手把手教你使用javascript+canvas开发一个塔防游戏01地图创建
项目演示 项目演示地址: 体验一下 项目源码: 项目源码 代码结构 本节做完效果 游戏主页面 index.html <!DOCTYPE html PUBLIC "-//W3C//DTD ...
- 谈谈hive中join下on和where
本文为博客园作者所写: 一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 很多人如果先接触mysql的执行顺序(from ->on ->join -&g ...
- Java Int类型与字符,汉字之间的转换
/** * java 中的流主要是分为字节流和字符流 * 再一个角度分析的话可以分为输入流和输出流 * 输入和输出是一个相对的概念 相对的分别是jvm虚拟机的内存大小 * 从另一个角度讲Java或者用 ...
- SecureCRT SSH Linux中不显示彩色 字体颜色、文件夹和文件显示的颜色区别开解决办法
SecureCRT SSH Linux中不显示彩色 字体颜色.文件夹和文件显示的颜色区别开解决办法 实验环境: 刚开始我的情况是这样的:带颜色的显示不出来,然后还能看到,此处有内容,猜测是Secure ...
- 远程调用post请求和get请求
/** * 获取用户 */ @RequestMapping("getUserMassages") public Map<String,Object> getuserMa ...
- java 数字和日期处理
static int abs(int a) 返回 a 的绝对值 static long abs(long a) 返回 a 的绝对值 static float abs(float a) 返回 a 的绝对 ...
- stm32学习笔记之SysTick的思考
原文来自--SevenZ的笔记.http://blog.21ic.com/user1/8247/archives/2011/85920.html ? 首先我们要明白什么是SysTick定时器? Sys ...
- mysql explain参数详解
主要对几个参数做一些记录 type:显示的是访问类型 从最好到最差的连接类型为:const.eq_reg.ref.range.index和ALL 至少要达到range,基本是ref 最好是const ...