转载地址:http://yhjhappy234.blog.163.com/blog/static/31632832201232410512971/
9、Semaphore
Semaphore是并发包中用于控制某个资源访问个数的类,例如数据库的连接池,我们用代码来演示一下一个连接池的实现:
packagecom.yhj.container.concurrent;
importjava.util.ArrayList;
importjava.util.List;
importjava.util.Random;
importjava.util.concurrent.BlockingQueue;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.LinkedBlockingQueue;
importjava.util.concurrent.Semaphore;
importjava.util.concurrent.TimeUnit;
/**
* @Described:基于信号量的测试用例
* @authorYHJ create at 2012-4-16 下午05:04:53
* @FileNmaecom.yhj.container.concurrent.SemaphoreTestCase.java
*/
publicclassSemaphoreTestCase {
//连接池
abstractclassPool{
protectedInteger maxActiveConnectionNum;
protectedInteger currentActiveConnectionNum;
protectedInteger maxWaitTime;
protectedList pools_used;
protectedBlockingQueue pools_free;
//构造器
protectedPool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
this.maxActiveConnectionNum= maxActiveConnectionNum;
this.currentActiveConnectionNum= currentActiveConnectionNum;
this.maxWaitTime= maxWaitTime;
this.pools_free= newLinkedBlockingQueue(maxActiveConnectionNum);
this.pools_used= newArrayList(maxActiveConnectionNum);
init();//直接创建最大的容量 本示例未做初始化不足扩容处理
}
privatevoidinit(){
for(inti=0;i
pools_free.add(newConnection());
}
//获取连接
publicabstractConnection getConnection();
//关闭连接
publicabstractvoidcloseConnection(Connection connection);
}
//连接供体
classConnection{
publicConnection() {System.out.println("创建了新的Connection : "+this);}
}
//普通连接池实现方案
classNormalPool extendsPool{
protectedNormalPool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
super(maxActiveConnectionNum, currentActiveConnectionNum, maxWaitTime);
}
@Override
publicConnection getConnection() {
Connection connection = null;
synchronized(pools_free) {
try{
//case 1# init
connection = pools_free.poll(maxWaitTime, TimeUnit.MILLISECONDS);
//case 2# init
//for(int i=0;i
// connection = pools_free.poll();
// if(null!=connection) break;
// wait(1);//防止过度消耗CPU
//}
//以下为case1和case2共同的部分 建议选用case1 精度级别为纳秒case2的精度级别 毫秒
//long waitTime = maxWaitTime - (System.currentTimeMillis()-beginTime);
//wait(waitTime);
if(null==connection)
thrownewRuntimeException("Connection timepit with "+maxWaitTime+" milliseconds");
else{
pools_used.add(connection);
System.out.println(Thread.currentThread().getName()+"获取连接"+connection);
returnconnection;
}
} catch(Exception e) {
thrownewRuntimeException(e);
}
}
}
@Override
publicvoidcloseConnection(Connection connection){
synchronized(pools_used) {
if(pools_used.remove(connection)){
pools_free.add(connection);
}
System.out.println(Thread.currentThread().getName()+"释放连接"+connection);
connection = null;
}
}
}
//基于信号量的连接池
classSemaphorePool extendsPool{
privateSemaphore semaphore;
protectedSemaphorePool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
super(maxActiveConnectionNum, currentActiveConnectionNum, maxWaitTime);
semaphore= newSemaphore(maxActiveConnectionNum, true);
}
@Override
publicConnection getConnection() {
Connection connection = null;
try{
if(semaphore.tryAcquire(maxWaitTime,TimeUnit.MILLISECONDS)){
synchronized(pools_free) {
connection = pools_free.poll();
if(null== connection)
thrownewRuntimeException("NullPointException in connection free pools");
pools_used.add(connection);
System.out.println(Thread.currentThread().getName()+"获取连接"+connection);
returnconnection;
}
}else{
thrownewRuntimeException("Connection timepit with "+maxWaitTime+" milliseconds");
}
} catch(InterruptedException e) {
thrownewRuntimeException(e);
}
}
@Override
publicvoidcloseConnection(Connection connection) {
synchronized(pools_used) {
if(pools_used.remove(connection)){
pools_free.add(connection);
}
semaphore.release();
System.out.println(Thread.currentThread().getName()+"释放连接"+connection);
connection = null;
}
}
}
//待执行的任务
classTask implementsRunnable{
privateRandom random= newRandom();
privatePool pool;
publicTask(Pool pool) {
this.pool= pool;
}
@Override
publicvoidrun() {
try{
Connection connection = pool.getConnection();
Thread.sleep(random.nextInt(1000));
pool.closeConnection(connection);
} catch(InterruptedException e) {
}
}
}
//启动函数
publicvoidstart(){
intthredCount = 100;
Pool pool = newNormalPool(10, 10, 100);
ExecutorService service = Executors.newCachedThreadPool();
for(inti=0;i
service.execute(newTask(pool));
}
service.shutdown();
pool = newSemaphorePool(10, 10, 100);
service = Executors.newCachedThreadPool();
for(inti=0;i
service.execute(newTask(pool));
}
service.shutdown();
}
publicstaticvoidmain(String[] args) {
newSemaphoreTestCase().start();
}
}
运行程序,我们发现如下结果:
很显然,
pool-1-thread是第一个线程池的数据,县创建对应的DB连接,然后有很多线程来回去这些连接,随后线程池2进行和创建和分配操作。但是很显然,100ms的超时时间不能承载1~1000ms之间的线程等待,显然中间会产生超时的问题,如下图所示:
同时我们看到中间有连接释放和连接获取的过程。但是拉到最后我们可以看到,
pool-2很早就完成了,但是pool1还在执行,如下图所示
CountDownLatch
、CyclicBarrier我们在上面的例子中也用到了,分别被用在多线程下做计数器和集合点(其实是另一种计数器),用户控制多线程下的并发操作。而在并罚中还会经常用到的一个锁是ReentrantLock和ReentrantReadWriteLock。我们分别来看一下:
packagecom.yhj.container.concurrent;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.CyclicBarrier;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
importjava.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @Described:读写分离的互斥锁 测试用例
* @authorYHJ create at 2012-4-23 下午09:22:53
* @FileNmaecom.yhj.container.concurrent.ReentrantReedWriteLockTestCase.java
*/
publicclassReentrantReadWriteLockTestCase {
privateMap map= newHashMap();
privateCountDownLatch latch;//计数器
privateCyclicBarrier barrier;//集合点
//任务
abstractclassTask implementsRunnable{
protectedLock lock;
publicTask(Lock lock) {this.lock= lock;}
@Override
publicvoidrun() {
try{
barrier.await();//到达集合点之前 等待
} catch(Exception e) {
e.printStackTrace();
}
try{
lock.lock(); //锁数据
process();
Thread.sleep(100);//等待100ms
} catch(Exception e) {
e.printStackTrace();
} finally{
lock.unlock();//解锁
latch.countDown();
}
}
//真正的业务
abstractprotectedvoidprocess();
}
//读任务
classReadTask extendsTask{
publicReadTask(Lock lock) {super(lock);}
@Override
protectedvoidprocess() {
map.get("test");
}
}
//读任务
classWriteTask extendsTask{
publicWriteTask(Lock lock) {super(lock);}
@Override
protectedvoidprocess() {
map.put("test", "case");
}
}
//初始化
privatevoidinit(intthredCount){
latch= newCountDownLatch(thredCount);
barrier= newCyclicBarrier(thredCount);
}
//计算耗时
privatevoidcalculateTimeCost(longbeginTime){
try{
latch.await();
System.out.println("total time cost "+(System.currentTimeMillis()-beginTime)+" ms");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
//启动函数
publicvoidstart(){
intwriteThredCount = 100,readThredCount = 400;
ExecutorService service = Executors.newCachedThreadPool();
//计算使用ReentrantReadWriteLock耗时
init(writeThredCount+readThredCount);
ReentrantReadWriteLock reentrantReadWriteLock = newReentrantReadWriteLock();
longbeginTime = System.currentTimeMillis();
for(inti=0;i
service.execute(newWriteTask(reentrantReadWriteLock.writeLock()));
for(inti=0;i
service.execute(newReadTask(reentrantReadWriteLock.readLock()));
calculateTimeCost(beginTime);
//计算使用ReentrantLock的耗时
init(writeThredCount+readThredCount);
ReentrantLock reentrantLock = newReentrantLock();
beginTime = System.currentTimeMillis();
for(inti=0;i
service.execute(newWriteTask(reentrantLock));
for(inti=0;i
service.execute(newReadTask(reentrantLock));
calculateTimeCost(beginTime);
service.shutdownNow();
}
//主函数
publicstaticvoidmain(String[] args) {
newReentrantReadWriteLockTestCase().start();
}
}
我们很清楚的看到,在并发情况下,读写锁分离明显优于一把锁。尤其是在读多写少的环境。
Condition。
Condition主要用于控制锁在并发下的唤醒和等待操作,其API说明如下:
以下是官方的一个示例代码,如下所示:
classBoundedBuffer {
finalLock lock= newReentrantLock();
finalCondition notFull= lock.newCondition();
finalCondition notEmpty= lock.newCondition();
finalObject[] items= newObject[100];
intputptr, takeptr, count;
publicvoidput(Object x) throwsInterruptedException {
lock.lock();
try{
while(count== items.length)
notFull.await();
items[putptr] = x;
if(++putptr== items.length) putptr= 0;
++count;
notEmpty.signal();
} finally{
lock.unlock();
}
}
publicObject take() throwsInterruptedException {
lock.lock();
try{
while(count== 0)
notEmpty.await();
Object x = items[takeptr];
if(++takeptr== items.length) takeptr= 0;
--count;
notFull.signal();
returnx;
} finally{
lock.unlock();
}
}
}
以上便是我们实际中可能经常要用到的一些并发包的类,由于时间和精力的原因,在这里也没写那么的详细,当然更多的还是实践,只有实践多了,我们才能更熟练的掌握这些并发相关的知识!