Java中Semaphore(信号量) 数据库连接池

计数信号量用来控制同时访问某个特定资源的操作数或同时执行某个指定操作的数量

A counting semaphore.Conceptually, a semaphore maintains a set of permits. Each acquire blocks if necessary until a permit is available, and then takes it. Each release adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.

从概念上来说,Semaphore中维护了一组许可,许可的数量在构造函数中指定。acquire方法将获取一个可用的许可,如果没有可用的许可,该方法会被阻塞,直到Semaphore中有可用的许可。release方法释放一个许可,如果此时存在阻塞中的acqure方法,将释放一个阻塞中的acquire

事实上,Semaphore中只维护可用请求数量,并不包含实际的请求对象

示例一:数据库连接池

在初始化Semaphore时可以设置其公平性,如果为公平Semaphore,则按照请求时间获得许可,即先发送的请求先获得许可,如果为非公平Semaphore,则先发送的请求未必先获得许可,这有助于提高程序的吞吐量,但是有可能导致某些请求始终获取不到许可(tryAcquire方法不使用公平性设置)

[java] view plaincopy
  1. import java.sql.Connection;  
  2. import java.sql.DriverManager;  
  3. import java.util.HashMap;  
  4. import java.util.LinkedList;  
  5. import java.util.Map;  
  6. import java.util.concurrent.Semaphore;  
  7.   
  8. public class MyConnPool {  
  9.     private LinkedList<Connection> unusedConns =   
  10.         new LinkedList<Connection>();  
  11.     //释放连接时对查找性能要求较高,故使用哈希表  
  12.     private Map<Connection,String> usedConns =   
  13.             new HashMap<Connection,String>();  
  14.     private final Semaphore available;  
  15.       
  16.     public MyConnPool(int size) throws Exception{  
  17.         StringBuilder builder = new StringBuilder();  
  18.         builder.append("-----pool-----\n");  
  19.         available = new Semaphore(size, true);//公平性Semaphore  
  20.         String url = "jdbc:mysql://ip:port/name?user=user&password=pwd";  
  21.         for(int i = 0 ; i < size ; i++){  
  22.             Connection conn = DriverManager.getConnection(url);  
  23.             unusedConns.add(conn);  
  24.             builder.append("conn-" + i + ":" + conn.hashCode() + "\n");  
  25.         }  
  26.         builder.append("--------------\n");  
  27.         System.out.print(builder.toString());  
  28.     }  
  29.       
  30.     public Connection getConn() throws InterruptedException{  
  31.         //获取Semaphore中的许可  
  32.         available.acquire();  
  33.         Connection conn = null;  
  34.         synchronized(this){  
  35.             conn = unusedConns.removeFirst();  
  36.             usedConns.put(conn, "");  
  37.               
  38.             System.out.println(Thread.currentThread().getName()  
  39.                     + ":" + conn.hashCode() + "[got]");  
  40.             System.out.println(display());  
  41.         }  
  42.         return conn;  
  43.     }  
  44.       
  45.     public void close(Connection conn){  
  46.         synchronized(this){  
  47.             if(usedConns.containsKey(conn)){  
  48.                 usedConns.remove(conn);  
  49.                 unusedConns.addLast(conn);  
  50.                   
  51.                 System.out.println(Thread.currentThread().getName()  
  52.                         + ":" + conn.hashCode() + "[closed]");  
  53.                 System.out.println(display());  
  54.             }  
  55.         }  
  56.         //释放线程获取的许可  
  57.         available.release();  
  58.     }  
  59.       
  60.     private final synchronized String display(){  
  61.         String str = "";  
  62.         if(unusedConns.size() > 0){  
  63.             str = "";  
  64.             for(Connection conn : unusedConns){  
  65.                 str += conn.hashCode() + "|";  
  66.             }  
  67.         }  
  68.         if(!str.equals(""))  
  69.             return str;  
  70.         else  
  71.             return "empty";  
  72.     }  
  73. }  
[java] view plaincopy
  1. import java.sql.Connection;  
  2. import java.util.concurrent.CountDownLatch;  
  3.   
  4. public class Test implements Runnable{  
  5.     private static CountDownLatch latch   
  6.             = new CountDownLatch(1);  
  7.     private MyConnPool pool;  
  8.       
  9.     public Test(MyConnPool pool){  
  10.         this.pool = pool;  
  11.     }  
  12.       
  13.     @Override  
  14.     public void run(){   
  15.         try {  
  16.             latch.await();  
  17.             Connection conn = pool.getConn();  
  18.             Thread.sleep(1*1000);  
  19.             pool.close(conn);  
  20.         } catch (InterruptedException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  
  24.       
  25.     public static void main(String[] args) throws Exception{  
  26.         MyConnPool pool = new MyConnPool(2);  
  27.         for(int i = 0 ; i < 4 ; i++){  
  28.             Thread t = new Thread(new Test(pool));  
  29.             t.start();  
  30.         }  
  31.         //保证4个线程同时运行  
  32.         latch.countDown();  
  33.     }  
  34. }  

运行结果如下:

[plain] view plaincopy
  1. -----pool-----  
  2. conn-0:11631043  
  3. conn-1:14872264  
  4. --------------  
  5. Thread-4:11631043[got]  
  6. 14872264|  
  7. Thread-1:14872264[got]  
  8. empty  
  9. Thread-4:11631043[closed]  
  10. 11631043|  
  11. Thread-2:11631043[got]  
  12. empty  
  13. Thread-1:14872264[closed]  
  14. 14872264|  
  15. Thread-3:14872264[got]  
  16. empty  
  17. Thread-2:11631043[closed]  
  18. 11631043|  
  19. Thread-3:14872264[closed]  
  20. 11631043|14872264|  

特别注意如果getConn方法和close方法都为同步方法,将产生死锁:

[java] view plaincopy
  1. public synchronized Connection getConn() throws InterruptedException{  
  2.     ......  
  3. }  
  4.       
  5. public synchronized void close(Connection conn){  
  6.     ......  
  7. }  

同一时刻只能有一个线程调用连接池的getConn方法或close方法,当Semaphore中没有可用的许可,并且此时恰好有一个线程成功调用连接池的getConn方法,则该线程将一直阻塞在acquire方法上,其它线程将没有办法获取连接池上的锁并调用close方法释放许可,程序将会卡死

阻塞方法上不要加锁,否则将导致锁长时间不释放,如果该锁为互斥锁,将导致程序卡住

acquire方法本身使用乐观锁实现,也不需要再加互斥锁

示例二:不可重入互斥锁

[java] view plaincopy
  1. import java.util.concurrent.CountDownLatch;  
  2. import java.util.concurrent.Semaphore;  
  3.   
  4. public class Test implements Runnable{  
  5.     private static CountDownLatch latch =  
  6.             new CountDownLatch(1);  
  7.     private static Semaphore lock =  
  8.             new Semaphore(1, true);  
  9.       
  10.     @Override  
  11.     public void run(){   
  12.         try {  
  13.             latch.await();  
  14.             this.work();  
  15.         } catch (InterruptedException e) {  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19.       
  20.     private void work() throws InterruptedException{  
  21.             lock.acquire();  
  22.             System.out.println("Locking by "   
  23.                     + Thread.currentThread().getName());  
  24.             Thread.sleep(1*1000);  
  25.             lock.release();  
  26.     }  
  27.       
  28.     public static void main(String[] args) throws Exception{  
  29.         for(int i = 0 ; i < 4 ; i++){  
  30.             Thread t = new Thread(new Test());  
  31.             t.start();  
  32.         }  
  33.         //保证4个线程同时运行  
  34.         latch.countDown();  
  35.     }  
  36. }  

运行结果如下:

[plain] view plaincopy
  1. Locking by Thread-3  
  2. Locking by Thread-0  
  3. Locking by Thread-1  
  4. Locking by Thread-2  

 

转载于:https://www.cnblogs.com/jiangzhaowei/p/7221208.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual Studio for Mac Preview离线下载安装

Visual Studio for Mac离线下载安装。 环境&#xff1a;OS X EI Caption 10.11.2 .NET Core SDK 1.1 需预先安装 .NET Core 1.1 SDK macOS版下载地址:https://go.microsoft.com/fwlink/?LinkID835011 安装SDK需先安装openssl。 brew update brew install openssl mkdir -p /us…

LOAM_velodyne学习(一)

在研读了论文及开源代码后&#xff0c;对LOAM的一些理解做一个整理。 文章&#xff1a;Low-drift and real-time lidar odometry and mapping 开源代码&#xff1a;https://github.com/daobilige-su/loam_velodyne 系统概述 LOAM的整体思想就是将复杂的SLAM问题分为&#x…

实战Vue简易项目(2)定制开发环境

本章内容包含上一章思考的解决&#xff0c;还有一些其它的定制... CSS预处理 关于对.vue文件模块处理规则的配置依次可在build/webpack.base.conf.js->build/vue-loader.conf.js->build/utils.js文件中跟踪&#xff1b; 而loaders的关键在于build/vue-loader.conf.js文件…

LINUX framebuffer

http://wangshh03.blog.163.com/blog/static/49103415201001231317484/ 一、FrameBuffer的原理 FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。 Linux是工作在保护模式下&#xff0c;所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏&…

[POI2007]POW-The Flood

题目描述 给定一张地势图&#xff0c;所有的点都被水淹没&#xff0c;现在有一些关键点&#xff0c;要求放最少的水泵使所有关键点的水都被抽干 输入输出格式 输入格式&#xff1a; In the first line of the standard input there are two integers and , separated by a sin…

LOAM_velodyne学习(二)

LaserOdometry 这一模块&#xff08;节点&#xff09;主要功能是&#xff1a;进行点云数据配准&#xff0c;完成运动估计 利用ScanRegistration中提取到的特征点&#xff0c;建立相邻时间点云数据之间的关联&#xff0c;由此推断lidar的运动。我们依旧从主函数开始&#xff1…

户外穿越

晚上很早就睡了&#xff0c;并且&#xff0c;太过激动&#xff0c;所以早上四点五十分就被惊醒&#xff0c;然后到早上闹钟响。 早上匆匆忙吃过早餐&#xff0c;就赶去坐车&#xff0c;到登山之前&#xff0c;坐了大巴车&#xff0c;又坐了景区的车&#xff0c;景区的路是山路十…

【oracle】关于创建表时用default指定默认值的坑

刚开始学create table的时候没注意&#xff0c;学到后面发现可以指定默认值。于是写了如下语句&#xff1a; 当我查询的时候发现&#xff0c;查出来的结果是这样的。。 很纳闷有没有&#xff0c;我明明指定默认值了呀&#xff0c;为什么创建出来的表还是空的呢&#xff1f;又跑…

Makefile中用宏定义进行条件编译(gcc -D)/在Makefile中进行宏定义-D

在源代码里面如果这样是定义的&#xff1a; #ifdef MACRONAME //可选代码 #endif 那在makefile里面 gcc -D MACRONAMEMACRODEF 或者 gcc -D MACRONAME 这样就定义了预处理宏&#xff0c;编译的时候可选代码就会被编译进去了。 对于GCC编译器&#xff0c;有如下选项&…

python安装与配置

首先下载python地址&#xff1a; https://www.python.org/downloads/release/python-361/下载页面中有多个版本&#xff1a; web-based installer 是需要通过联网完成安装的 executable installer 是可执行文件(*.exe)方式安装 embeddable zip file 嵌入式版本&#xff0c;可…

[OpenGL ES 03]3D变换:模型,视图,投影与Viewport

[OpenGL ES 03]3D变换&#xff1a;模型&#xff0c;视图&#xff0c;投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循“署名-非商业用途-保持一致”创作公用协议 系列文章&#xff1a;[OpenGL ES 01]OpenGL ES之初体验[OpenGL ES 02]OpenGL ES渲染管线与着色器…

LOAM_velodyne学习(三)

终于到第三个模块了&#xff0c;我们先来回顾下之前的工作&#xff1a;点云数据进来后&#xff0c;经过前两个节点的处理可以完成一个完整但粗糙的里程计&#xff0c;可以概略地估计出Lidar的相对运动。如果不受任何测量噪声的影响&#xff0c;这个运动估计的结果足够精确&…

监控视频线种类 视频信号传输介绍及各种视频接口的传输距离

一.视频信号接口 监控视频线种类介绍&#xff1a; 按照材料区分有SYV及SYWV两种&#xff0c;绝缘层的物理材料结构不同&#xff0c;SYV是实心聚乙烯电缆&#xff0c;SYWV是高物理发泡电缆&#xff0c;物理发泡电缆传输性能优于聚乙烯。 S--同轴电缆 Y--聚乙烯 V--聚氯乙烯 W…

免费节假日API 更新新功能了 新增农历信息返回

感谢大家对免费节假日API的支持.最近看了别家的api于是增加了一些新功能即获取日期的农历信息. 这个新功能还处于测试阶段如有问题欢迎反馈 检查一个日期是详细信息 https://tool.bitefu.net/jiari/?d20180101&info1 返回值 {"status": 1,"type": 1,…

新手算法学习之路----二叉树(二叉树最大路径和)

摘抄自&#xff1a;https://segmentfault.com/a/1190000003554858#articleHeader2 题目&#xff1a; Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. For example: Given the below binary tree, 1/ \2 3Return 6. 思…

Ajax工作原理

详见&#xff1a;http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt238 在这篇文章中&#xff0c;我将从10个方面来对AJAX技术进行系统的讲解。 1、ajax技术的背景 不可否认&#xff0c;ajax技术的流行得益于google的大力推广&#xff0c;正是由于google earth、go…

各种视频信号格式及端子介绍/VGA DVI HDMI区别

视频信号是我们接触最多的显示信号&#xff0c;但您并不一定对各种视频信号有所了解。因为国内用到的视频信号格式和端子非常有限&#xff0c;一般就是复合视频和S端子&#xff0c;稍高级一些的就是色差及VGA。对于那些经常接触国外电器和二手设备的朋友&#xff0c;就会遇到各…

LOAM_velodyne学习(四)

TransformMaintenance 来到了最后一个模块&#xff0c;代码不是很长&#xff0c;我们在看完代码之后&#xff0c;再详细说明这个模块的功能 依然主函数开始 int main(int argc, char** argv) {ros::init(argc, argv, "transformMaintenance");ros::NodeHandle nh;…

PHP数据库类

<?phpclass Db{//私有静态属性存储实例化对象自身private static $instance;//存储PDO类的实例化private $pdo;//PDOStatement类private $stmt;//禁止外部实例化对象&#xff0c;链接数据库private function __construct($config,$port,$charset){try{$this->pdo new P…

oracle参数文件、控制文件、数据文件、日志文件的位置及查询方法

参数文件&#xff1a;所有参数文件一般在 $ORACLE_HOME/dbs 下 sqlplus查询语句&#xff1a;show parameter spfile; 网络连接文件&#xff1a; $ORACLE_HOME/dbs/network/admin 目录中 控制文件&#xff1a;select * from v$controlfile; 数据文件&#xff1a;一般在oracleda…