java实现并发连接池_java并发实战:连接池实现
池化技术简介
在我们使用数据库的过程中,我们往往使用数据库连接池而不是直接使用数据库连接进行操作,这是因为每一个数据库连接的创建和销毁的代价是昂贵的,而池化技术则预先创建了资源,这些资源是可复用的,这样就保证了在多用户情况下只能使用指定数目的资源,避免了一个用户创建一个连接资源,造成程序运行开销过大。关于Java并发编程的总结和思考
连接池实现原理
这里只实现一个简易的连接池,更多复杂的需求可根据该连接池进行改进,该连接池主要参数如下:
- 一个繁忙队列busy
- 一个空闲队列idle
- 连接池最大活动连接数maxActive
- 连接池最大等待时间maxWait
- 连接池的活动连接数activeSize
程序流程图如下:
代码实现
泛型接口ConnectionPool.java
public interface ConnectionPool<T> {
/**
* 初始化池资源
* @param maxActive 池中最大活动连接数
* @param maxWait 最大等待时间
*/
void init(Integer maxActive, Long maxWait);
/**
* 从池中获取资源
* @return 连接资源
*/
T getResource() throws Exception;
/**
* 释放连接
* @param connection 正在使用的连接
*/
void release(T connection) throws Exception;
/**
* 释放连接池资源
*/
void close();
}
以zookeeper为例,实现zookeeper连接池,ZookeeperConnectionPool.java
public class ZookeeperConnectionPool implements ConnectionPool<ZooKeeper> {
//最大活动连接数
private Integer maxActive;
//最大等待时间
private Long maxWait;
//空闲队列
private LinkedBlockingQueue<ZooKeeper> idle = new LinkedBlockingQueue<>();
//繁忙队列
private LinkedBlockingQueue<ZooKeeper> busy = new LinkedBlockingQueue<>();
//连接池活动连接数
private AtomicInteger activeSize = new AtomicInteger(0);
//连接池关闭标记
private AtomicBoolean isClosed = new AtomicBoolean(false);
//总共获取的连接记数
private AtomicInteger createCount = new AtomicInteger(0);
//等待zookeeper客户端创建完成的计数器
private static ThreadLocal<CountDownLatch> latchThreadLocal = ThreadLocal.withInitial(() -> new CountDownLatch(1));
public ZookeeperConnectionPool(Integer maxActive, Long maxWait) {
this.init(maxActive, maxWait);
}
@Override
public void init(Integer maxActive, Long maxWait) {
this.maxActive = maxActive;
this.maxWait = maxWait;
}
@Override
public ZooKeeper getResource() throws Exception {
ZooKeeper zooKeeper;
Long nowTime = System.currentTimeMillis();
final CountDownLatch countDownLatch = latchThreadLocal.get();
//空闲队列idle是否有连接
if ((zooKeeper = idle.poll()) == null) {
//判断池中连接数是否小于maxActive
if (activeSize.get() < maxActive) {
//先增加池中连接数后判断是否小于等于maxActive
if (activeSize.incrementAndGet() <= maxActive) {
//创建zookeeper连接
zooKeeper = new ZooKeeper("localhost", 5000, (watch) -> {
if (watch.getState() == Watcher.Event.KeeperState.SyncConnected) {
countDownLatch.countDown();
}
});
countDownLatch.await();
System.out.println("Thread:" + Thread.currentThread().getId() + "获取连接:" + createCount.incrementAndGet() + "条");
busy.offer(zooKeeper);
return zooKeeper;
} else {
//如增加后发现大于maxActive则减去增加的
activeSize.decrementAndGet();
}
}
//若活动线程已满则等待busy队列释放连接
try {
System.out.println("Thread:" + Thread.currentThread().getId() + "等待获取空闲资源");
Long waitTime = maxWait - (System.currentTimeMillis() - nowTime);
zooKeeper = idle.poll(waitTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new Exception("等待异常");
}
//判断是否超时
if (zooKeeper != null) {
System.out.println("Thread:" + Thread.currentThread().getId() + "获取连接:" + createCount.incrementAndGet() + "条");
busy.offer(zooKeeper);
return zooKeeper;
} else {
System.out.println("Thread:" + Thread.currentThread().getId() + "获取连接超时,请重试!");
throw new Exception("Thread:" + Thread.currentThread().getId() + "获取连接超时,请重试!");
}
}
//空闲队列有连接,直接返回
busy.offer(zooKeeper);
return zooKeeper;
}
@Override
public void release(ZooKeeper connection) throws Exception {
if (connection == null) {
System.out.println("connection 为空");
return;
}
if (busy.remove(connection)){
idle.offer(connection);
} else {
activeSize.decrementAndGet();
throw new Exception("释放失败");
}
}
@Override
public void close() {
if (isClosed.compareAndSet(false, true)) {
idle.forEach((zooKeeper) -> {
try {
zooKeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
busy.forEach((zooKeeper) -> {
try {
zooKeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
测试用例
这里创建20个线程并发测试连接池,Test.java
public class Test {
public static void main(String[] args) throws Exception {
int threadCount = 20;
Integer maxActive = 10;
Long maxWait = 10000L;
ZookeeperConnectionPool pool = new ZookeeperConnectionPool(maxActive, maxWait);
CountDownLatch countDownLatch = new CountDownLatch(20);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
countDownLatch.countDown();
try {
countDownLatch.await();
ZooKeeper zooKeeper = pool.getResource();
Thread.sleep(2000);
pool.release(zooKeeper);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
while (true){
}
}
}
java实现并发连接池_java并发实战:连接池实现相关推荐
- java线程池_Java 并发编程 线程池源码实战
作者 | 马启航 杏仁后端工程师.「我头发还多,你们呢?」 一.概述 笔者在网上看了好多的关于线程池原理.源码分析相关的文章,但是说实话,没有一篇让我觉得读完之后豁然开朗,完完全全的明白线程池,要么写 ...
- java并发编程 目录_Java并发编程实战的作品目录
展开全部 对本书的赞誉 译者序 前 言 第1章 简介 1.1 并发简史 1.2 线程的优势 1.2.1 发挥多处理器的强大能力e5a48de588b662616964757a686964616f313 ...
- java池_java中的各种池
常量池.线程池.连接池 一.常量池 1.什么是常量 是一种值,这个值本身 例如:八大基本数据类型 加字符串 不可变的变量,被final修饰的 例如 final int i=1; String str= ...
- java中数据库连接池_Java中的数据库连接池
本文译自Baeldung的博客 概述 连接池是一种众所周知的数据库访问模式,主要目的是减少创建数据库连接和读/写数据库操作的开销. 简单来说,连接池本质上就是数据库连接缓存的一种实现方式,可以通过对其 ...
- java阿里数据库连接池_Java学习:数据库连接池技术
本节内容 数据库连接池 Spring JDBC : JDBC Template 数据库连接池 1.概念:其实就是一个容器(集合),存放数据库连接的容器 当系统初始化好后,容器中会申请一些连接对象,当用 ...
- java 队列线程池_JAVA工作队列与线程池
为什么要使用线程池? 诸如 Web 服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过网络协议 ...
- java统计系统线程数_Java并发(八)计算线程池最佳线程数
目录 一.理论分析 二.实际应用 为了加快程序处理速度,我们会将问题分解成若干个并发执行的任务.并且创建线程池,将任务委派给线程池中的线程,以便使它们可以并发地执行.在高并发的情况下采用线程池,可以有 ...
- java的尝试性问题_Java并发编程实战 03互斥锁 解决原子性问题
文章系列 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和有序性的问题,那么还有一个原子性问题咱们还没解决.在第一篇文章01并发编程的Bug源头当中,讲到了把一个或者多 ...
- java线程同步的实现_Java并发编程(三) - 实战:线程同步的实现
synchronized关键字 首先,来看一个多线程竞争临界资源导致的同步不安全问题. package com.example.weishj.mytester.concurrency.sync; /* ...
最新文章
- python输入输出有问题_python – Modbus错误:[输入/输出]无从远程...
- 1202: [HNOI2005]狡猾的商人
- mysql默认排序规则_mysql 字符集与排序规则的简单了解
- 电脑程序无法打开,开机5S后速度变慢,程序无法安装
- 【vim新手心得】最常用快捷键、编辑器vim插件使用心得(VsVim、IdeaVim、Vimium)
- Vert.x 异步访问数据库 MySQL
- Android ViewFlipper源码分析
- WebShell脚本检测机器学习二
- 预产期在线计算机,预产期计算器
- 10个精美免费PPT模板下载网站推荐
- 计算机软件行业新三板企业,2017福布斯值得关注的新三板企业榜:软件行业、互联网服务占据大半...
- Android仿微信语音聊天功能
- 栈(Stack)——后进先出(LIFO)的数据结构(Data Structures)
- 2021-08-11BUU-CTF:[WUSTCTF2020]alison_likes_jojo
- mysql数据库重做日志文件_数据库:mysql:重做日志文件(redo log file)
- 从0开始的网游ARPG实战案例:暗黑战神(第一章至第四章:设计登陆和创建角色功能实现)
- Spring boot如何集成Redis(四)
- r语言 柱状图加星号_如何用R画分组柱状图并且添加标准差和显著性标记(星号)?...
- 什么是AppImage
- 【halcon机器视觉教程】黑洞是什么洞?我来给你拍个照,黑洞成像系统
热门文章
- 上万规模数据湖如何在实验室测试
- 详解API Gateway流控实现,揭开ROMA平台高性能秒级流控的技术细节
- Scrum指南这么改,我看要完蛋!
- 【华为云技术分享】文字识别服务(OCR)基于对抗样本的模型可信安全威胁分析初析
- 利用 Flask 动态展示 Pyecharts 图表数据的几种方法
- 补习系列(7)-springboot 实现拦截的五种姿势
- python推导式pythonic必备
- 野生前端的数据结构练习(1)——栈
- 编写函数实现有序数组的二分查找
- 简易售货机JAVA sql_自动售货机 - 笨拙的小Q的个人空间 - OSCHINA - 中文开源技术交流社区...