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 ...
随机推荐
- Android实战技巧: ListView之ContextMenu无法弹出
问题 Activity中使用了ListView作为布局.当每一列表项中含有默认能获取焦点的子View时有可能会对ListView的某些事件有影响: 1. OnItemClick 2. OnItemLo ...
- MySQL学习笔记之中的一个 MySQL入门
本人之前接触的关系型数据库主要是oracle和sqlserver,而对于mysql知之甚少,但查阅网上资料发现,mysql与oracle非常相似,所以学起来应该不会非常费劲,在总结的时候可能很多其它的 ...
- Setup SSH and SVN on Windows Server
cygwin: install sshd, cygrunsrv http://lifehacker.com/205090/geek-to-live--set-up-a-personal-home-ss ...
- Keywords Search (ac 自己主动机)
Keywords Search Problem Description In the modern time, Search engine came into the life of everybod ...
- [Android学习笔记]Canvas的使用
Canvas文档 http://developer.android.com/training/index.html 在绘制view时候,重写onDraw(canvas)方法,可能需要在canvas上绘 ...
- 欧舒丹 L'Occitane 活力清泉保湿面霜 - 男士护肤 - 香港草莓网StrawberryNET.com
欧舒丹 L'Occitane 活力清泉保湿面霜 - 男士护肤 - 香港草莓网StrawberryNET.com 欧舒丹 活力清泉保湿面霜 50ml/1.7oz
- Python基础 - 迭代
前言 在pythone中经常可以看到iterable这样的描述. 直译为迭代. 这是在C中没有的概念. iterable(可迭代) 支持每次返回自己所包含的一个成员的对象就是可迭代对象. iterab ...
- 虚拟机VM10装Mac OS X 10.9.3
近期WWDC放出终极大招--新的编程语言Swift(雨燕),导致一大波程序猿的围观和跃跃欲试.当然了,工欲善其事,必先利其器,所以对于那些没有Mac又想要尝鲜的小伙伴肯定非常为难.可是,请放心,本文教 ...
- 基于Grunt的版本号构建系统新手教程
作者:zhanhailiang 日期:2014-10-12 1. 安装nodejs,npm,grunt-cli.參见<Windows环境下安装nodejs+npm+grunt-cli工具> ...
- Linux下搭建tomcat集群全记录(转)
本文将讲述如何在Linux下搭建tomcat集群,以及搭建过程中可能的遇到的问题和解决方法.为简单起见,本文演示搭建的集群只有两个tomact节点外加一个apache组成,三者将安装在同一机器上:ap ...