前面学习过等待 - 通知机制,现在我们在其基础上添加一个超时机制,模拟从连接池中获取、使用和释放连接的过程。客户端获取连接的过程被设定为等待超时模式,即如果在 1000 毫秒内无法获取到可用连接,将会返回给客户端一个 null。设定连接池的大小为 10 个,然后通过调节客户端的线程数来模拟无法获取连接的场景

由于 java.sql.Connection 只是一个接口,最终实现是由数据库驱动提供方来实现,考虑到本例只是演示,我们通过动态代理构造一个 Connection,该 Connection 的代理仅仅是在调用 commit() 方法时休眠 100 毫秒

public class ConnectionDriver {

    static class ConnectionHandler implements InvocationHandler {

        @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("commit".equals(method.getName())) {
TimeUnit.MICROSECONDS.sleep(100);
}
return null;
}
} /**
* 创建一个 Connection 的代理,在 commit 时休眠 100 毫秒
*/
public static Connection createConnection() {
return (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),
new Class<?>[]{Connection.class}, new ConnectionHandler());
}
}

接下来是线程池的实现。本例通过一个双向队列来维护连接,调用方需要先调用 fetchConnection(long) 方法来指定在多少毫秒内超时获取连接,当连接使用完成后,需要调用 releaseConnection(Connection) 方法将连接放回线程池

public class ConnectionPool {

    private final LinkedList<Connection> pool = new LinkedList<>();

    public ConnectionPool(int initialSize) {
// 初始化连接的最大上限
if (initialSize > 0) {
for (int i = 0; i < initialSize; i++) {
pool.addLast(ConnectionDriver.createConnection());
}
}
} public void releaseConnection(Connection connection) {
if (connection != null) {
synchronized (pool) {
/* 连接释放后需要进行通知
* 这样其他消费者就能知道连接池已经归还了一个连接
*/
pool.addLast(connection);
pool.notifyAll();
}
}
} /**
* 在给定毫秒时间内获取连接
*/
public Connection fetchConnection(long mills) throws InterruptedException {
synchronized (pool) {
// 完全超时
if (mills < 0) {
while (pool.isEmpty()) {
pool.wait();
}
return pool.removeFirst();
} else {
long future = System.currentTimeMillis() + mills;
long remaining = mills;
while (pool.isEmpty() && remaining > 0) {
pool.wait(remaining);
remaining = future - System.currentTimeMillis();
}
Connection result = null;
if (!pool.isEmpty()) {
result = pool.removeFirst();
}
return result;
}
}
}
}

最后编写一个用于模拟客户端获取连接的示例,该示例将模拟多个线程同时从连接池获取连接,并记录总尝试获取数、获取成功数和获取失败数

public class ConnectionPoolTest {

    static ConnectionPool pool = new ConnectionPool(10);
static CountDownLatch start = new CountDownLatch(1);
static CountDownLatch end; public static void main(String[] args) throws InterruptedException {
// 线程数量
int threadCount = 200;
end = new CountDownLatch(threadCount);
int count = 20;
AtomicInteger got = new AtomicInteger();
AtomicInteger notGot = new AtomicInteger();
for (int i = 0; i < threadCount; i++) {
Thread thread = new Thread(new ConnectionRunner(count, got, notGot), "ConnectionRunnerThread");
thread.start();
}
start.countDown();
end.await();
System.out.println("total invoke : " + (threadCount * count));
System.out.println("got connection : " + got);
System.out.println("not got connection : " + notGot);
} static class ConnectionRunner implements Runnable { int count;
AtomicInteger got;
AtomicInteger notGot; public ConnectionRunner(int count, AtomicInteger got, AtomicInteger notGot) {
this.count = count;
this.got = got;
this.notGot = notGot;
} @Override
public void run() {
try {
start.await();
} catch (Exception e) {
e.printStackTrace();
}
while (count > 0) {
try {
// 从线程池中获取连接,如果 1000ms 内无法获取到,将返回 null
// 分别统计获取连接的数量 got 和未获取到的数量 notGot
Connection connection = pool.fetchConnection(1000);
if (connection != null) {
try {
connection.createStatement();
connection.commit();
} finally {
pool.releaseConnection(connection);
got.incrementAndGet();
}
} else {
notGot.incrementAndGet();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
count--;
}
}
end.countDown();
}
}
}

笔者设置线程数量为 200 时,得出结果如下

当设置为 500 时,得出结果如下,当然具体结果根据机器性能而异

可见,随着客户端线程数的增加,客户端出现超时无法获取连接的比率不断升高。这种等待超时模式能保证程序出问题时,线程不会一直运行,而是按时返回,并告知客户端获取连接出现问题。数据库连接池的实际也可以应用到其他资源获取的场景,针对昂贵资源的获取都应该加以限制

Java 模拟数据库连接池的实现的更多相关文章

  1. java配置数据库连接池的方法步骤

    java配置数据库连接池的方法步骤 java配置数据库连接池的方法步骤,需要的朋友可以参考一下   先来了解下什么是数据库连接池数据库连接池技术的思想非常简单,将数据库连接作为对象存储在一个Vecto ...

  2. Java第三方数据库连接池库-DBCP-C3P0-Tomcat内置连接池

    连接池原理 数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”.预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去.我们可以通过设定连接池 ...

  3. Java中数据库连接池原理机制的详细讲解以及项目连接数据库采用JDBC常用的几种连接方式

    连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...

  4. java实现数据库连接池

    package com.kyo.connection; import java.sql.Connection; import java.sql.DatabaseMetaData; import jav ...

  5. Java jdbc数据库连接池总结!(转)

    1. 引言 近年来,随着Internet/Intranet建网技术的飞速发展和在世界范围内的迅速普及,计算机 应用程序已从传统的桌面应用转到Web应用.基于B/S(Browser/Server)架构的 ...

  6. 【Java】数据库连接池技术

    JDBC的问题 在程序中,我们经常要建立与数据库的连接,之后再关闭这个连接.我们知道,数据库连接对象的创建是比较消耗系统性能的,这些频繁的操作势必会消耗大量的系统资源.因此我们需要采用更高效的数据库访 ...

  7. java通过数据库连接池链接oracle

    开发工具:Eclipse J2EE 3.6 运行环境:jdk1.6 部署环境:Tomcat7 数据库连接池用的是dbcp,网上download下来的三个jar包. 把数据库连接池包和jdbc的包放到t ...

  8. java常用数据库连接池 (DBCP、c3p0、Druid) 配置说明

    1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...

  9. java之数据库连接池-dbcp&c3p0&dbutils

    介绍 因为数据库连接对象的创建比较消耗性能,所以可以在应用程序启动时就在内存中开辟一片空间(集合)存放多个数据库连接对象,后面需要连接时直接从该空间中取而不用新创建:使用完毕后归还连接(将连接重新放回 ...

  10. Java中数据库连接池原理机制的详细讲解

    连接池的基本工作原理 1.基本概念及原理 由上面的分析可以看出,问题的根源就在于对数据库连接资源的低效管理.我们知道,对于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式 ...

随机推荐

  1. Java基础知识(纯干货)

    基础篇 IDEA 开发 Java项目 卸载JDK 删除Java的安装目录 删除JAVA_HOME 删除path下关于java的目录 java -version 安装JDK17 下载链接:https:/ ...

  2. Jenkins从Ubuntu迁移至AlmaLinux问题及相关解决记录

    相关背景 之前在Ubuntu平台上搭建了Jenkins(在Ubuntu机器上使用war包安装Jenkins),现在由于一些需求,需要将系统迁移到AlmaLinux平台.由于AlmaLinux属于Cen ...

  3. 用友vs金蝶产品分析(云星空与YonSuite)

    产品定位 用友与金蝶二者面对的客户群体是相同的:都是为成长型企业提供一体化服务,由于金蝶云星空发展较早,在部分产品功能上具备一定的先发优势:在产品的架构上,由于YS采用目前最先进的云原生和微服务架构, ...

  4. Android OpenGL ES入门

    1.OpenGL 和OpenGL ES OpenGL(Open Graphics Library)是一种用于渲染2D和3D图形的跨平台编程接口.OpenGL提供了一套标准的函数和接口,使开发人员能够在 ...

  5. [ABC265B] Explore

    Problem Statement Takahashi is exploring a cave in a video game. The cave consists of $N$ rooms arra ...

  6. 聊聊流式数据湖Paimon(二)

    当前的问题 Apache Paimon 最典型的场景是解决了 CDC (Change Data Capture) 数据的入湖:CDC 数据来自数据库.一般来说,分析需求是不会直接查询数据库的. 容易对 ...

  7. Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schema

    什么是Json Schema ? Json Schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法. 利用Json Schema ...

  8. python3发送Gratuitous ARP更新vip绑定关系

    操作系统 :CentOS 7.6_x64 Python版本:3.9.12 FreeSWITCH版本 :1.10.9 高可用场景下,vip切换完成后需要发送arp广播更新ip和mac地址的绑定关系,如果 ...

  9. .net Core中间件实战

    新建一个ASP.NET Core Web Application 项目选中空模板 然后为项目添加一个Microsoft.Extensions.Logging.Console 由于我用的.net cor ...

  10. pyecharts 保存图表至本地

    pip install snapshot-selenium from pyecharts.render import make_snapshot from snapshot_selenium impo ...