Java 并发专题 : Semaphore 实现 互斥 与 连接池
继续并发方面的知识。今天介绍Semaphore,同样在java.util.concurrent包下。
本来准备通过例子,从自己实现到最后使用并发工具实现,但是貌似效果并不是很好,有点太啰嗦的感觉,所有准备直入主题。
介绍:Semaphore中管理着一组虚拟的许可,许可的初始数量可通过构造函数来指定【new Semaphore(1);】,执行操作时可以首先获得许可【semaphore.acquire();】,并在使用后释放许可【semaphore.release();】。如果没有许可,那么acquire方法将会一直阻塞直到有许可(或者直到被终端或者操作超时)。
作用:可以用来控制同时访问某个特定资源的操作数量,或者某个操作的数量。
下面使用Semaphore实现两个例子:
1、互斥
大家都学过操作系统,都知道互斥的概念,比较简单的互斥实现,比如PV操作,判断资源,然后忙等实现互斥;上一篇博客也说过,忙等对CPU的消耗巨大,下面我们通过Semaphore来实现一个比较好的互斥操作:
假设我们公司只有一台打印机,我们需要对这台打印机的打印操作进行互斥控制:
package com.zhy.concurrency.semaphore; import java.util.concurrent.Semaphore; /**
* 使用信号量机制,实现互斥访问打印机
*
* @author zhy
*
*/
public class MutexPrint
{ /**
* 定义初始值为1的信号量
*/
private final Semaphore semaphore = new Semaphore(1); /**
* 模拟打印操作
* @param str
* @throws InterruptedException
*/
public void print(String str) throws InterruptedException
{
//请求许可
semaphore.acquire(); System.out.println(Thread.currentThread().getName()+" enter ...");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "正在打印 ..." + str);
System.out.println(Thread.currentThread().getName()+" out ...");
//释放许可
semaphore.release();
} public static void main(String[] args)
{
final MutexPrint print = new MutexPrint(); /**
* 开启10个线程,抢占打印机
*/
for (int i = 0; i < 10; i++)
{
new Thread()
{
public void run()
{
try
{
print.print("helloworld");
} catch (InterruptedException e)
{
e.printStackTrace();
}
};
}.start();
} } }
输出结果:
Thread-1 enter ...
Thread-1正在打印 ...helloworld
Thread-1 out ...
Thread-2 enter ...
Thread-2正在打印 ...helloworld
Thread-2 out ...
Thread-0 enter ...
Thread-0正在打印 ...helloworld
Thread-0 out ...
Thread-3 enter ...
Thread-3正在打印 ...helloworld
Thread-3 out ...
通过初始值为1的Semaphore,很好的实现了资源的互斥访问。
2、连接池的模拟实现
在项目中处理高并发时,一般数据库都会使用数据库连接池,假设现在数据库连接池最大连接数为10,当10个连接都分配出去以后,现在有用户继续请求连接,可能的处理:
a、手动抛出异常,用户界面显示,服务器忙,稍后再试
b、阻塞,等待其他连接的释放
从用户体验上来说,更好的选择当然是阻塞,等待其他连接的释放,用户只会觉得稍微慢了一点,并不影响他的操作。下面使用Semaphore模拟实现一个数据库连接池:
package com.zhy.concurrency.semaphore; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
/**
* 使用Semaphore模拟数据库链接池的使用
* @author zhy
*
*/
public class ConnectPool
{
private final List<Conn> pool = new ArrayList<Conn>(3);
private final Semaphore semaphore = new Semaphore(3); /**
* 初始化分配3个连接
*/
public ConnectPool()
{
pool.add(new Conn());
pool.add(new Conn());
pool.add(new Conn());
} /**
* 请求分配连接
* @return
* @throws InterruptedException
*/
public Conn getConn() throws InterruptedException
{
semaphore.acquire();
Conn c = null ;
synchronized (pool)
{
c = pool.remove(0);
}
System.out.println(Thread.currentThread().getName()+" get a conn " + c);
return c ;
} /**
* 释放连接
* @param c
*/
public void release(Conn c)
{
pool.add(c);
System.out.println(Thread.currentThread().getName()+" release a conn " + c);
semaphore.release();
} public static void main(String[] args)
{ final ConnectPool pool = new ConnectPool(); /**
* 第一个线程占用1个连接3秒
*/
new Thread()
{
public void run()
{
try
{
Conn c = pool.getConn();
Thread.sleep(3000);
pool.release(c);
} catch (InterruptedException e)
{
e.printStackTrace();
}
};
}.start();
/**
* 开启3个线程请求分配连接
*/
for (int i = 0; i < 3; i++)
{
new Thread()
{
public void run()
{
try
{
Conn c = pool.getConn();
} catch (InterruptedException e)
{
e.printStackTrace();
}
};
}.start();
} } private class Conn
{
} }
Thread-0 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
Thread-2 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@e53108
Thread-1 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@1888759
Thread-0 release a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
Thread-3 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
我们测试时,让Thread-0持有一个连接3秒,然后瞬间让3个线程再去请求分配连接,造成Thread-3一直等到Thread-0对连接的释放,然后获得连接。
通过两个例子,基本已经了解了Semaphore的用法,这里的线程池例子只是为了说明Semaphore的用法,真实的实现代码比这复杂的多,而且可能也不会直接用Semaphore。
好了,之后会继续Java并发的博客。
Java 并发专题 : Semaphore 实现 互斥 与 连接池的更多相关文章
- Java并发编程实战 03互斥锁 解决原子性问题
文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...
- Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理
Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...
- Java并发编程(您不知道的线程池操作)
Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...
- Java并发(二十一):线程池实现原理
一.总览 线程池类ThreadPoolExecutor的相关类需要先了解: (图片来自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8% ...
- 【Java 并发】Executor框架机制与线程池配置使用
[Java 并发]Executor框架机制与线程池配置使用 一,Executor框架Executor框架便是Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下 ...
- java并发编程笔记(七)——线程池
java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...
- Java并发专题
——参考于码农求职小助手公众号 1.并行和并发有什么区别? 1. 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生: 2. 并行是在不同实体上的多个事件,并发是在同一 ...
- Java 并发专题 :FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等
继续并发专题~ FutureTask 有点类似Runnable,都可以通过Thread来启动,不过FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞. 由于:Fu ...
- Java 并发专题 : CyclicBarrier 打造一个安全的门禁系统
继续并发专题~ 这次介绍CyclicBarrier:看一眼API的注释: /** * A synchronization aid that allows a set of threads to all ...
随机推荐
- TCP连接的建立(二)
被动打开 SYN cookies TCP协议开辟了一个比較大的内存空间请求连接队列来存储连接请求块,当SYN请求不断添加,请求连接数目到达上限时,会致使系统丢弃SYN连接请求.SYN cookies技 ...
- 如何用jsp页面生成随机的验证数字码
checkNum.jsp <%@ page language="java" import="java.util.*,java.sql.*" pageEnc ...
- 数字证书, 数字签名, SSL(TLS) , SASL .
因为项目中要用到TLS + SASL 来做安全认证层. 所以看了一些网上的资料, 这里做一个总结. 1. 首先推荐几个文章: 数字证书: http://www.cnblogs.com/hyddd/ar ...
- JVM内存配置详解(转)
前段时间在一个项目的性能测试中又发生了一次OOM(Out of swap sapce),情形和以前网店版的那次差不多,比上次更奇怪的是,此次搞了几天之后啥都没调整系统就自动好了,死活没法再重现之前的O ...
- ZXing拍摄代码扫描之后以区分一维码、二维码、其他代码
我怎么有二维码没有联系,最近遇到一个问题,,如何推断条码扫描到一维代码或者二维代码,辛苦了一个下午下班后自己,加上网上跟踪信息. 总结出两种方式能够解决该问题(推荐採用另外一种方式): 1.改动源代码 ...
- hdoj 1258 SUM IT UP
程序的思想是:输入数据是,先使用快排对其从大到小进行排序,然后记录相同数据的个数,比如4 3 3 2 2 1 1,最后的数据变成4 3 2 1 ,并且同时数据的个数f[]变成1 2 2 2 然后就是遍 ...
- Java跨域设置
Access-Control-Allow-Origin 为允许哪些Origin发起跨域请求. 这里设置为"*"表示允许所有,通常设置为所有并不安全,最好指定一下. Access-C ...
- POJ 1742 Coins ( 单调队列解法 )
id=1742" target="_blank">题目链接~~> 做题感悟:第一次做的时候用的二进制优化.可是没注意到是险过.so也没去看单调队列的解法. 解 ...
- cocoapod安装失败解决
cocoapods 是 iOS 上不错的包依赖管理软件,在前面的文章里衣服自己洗是有做简单的介绍.最近在学习iOS开发,中间碰到安装cocoapods一些问题,具体的安装教程网上非常多,大家搜一下久可 ...
- tomcat启动Flash退出错误不能被视为解决该错误信息
tomcat 当有错误 启动startup.bat闪存在退出解决方案 打开 startup.bat 文件 最后 该start 阅读run watermark/2/text/aHR0cDovL2Jsb2 ...