Java并发包中常用类小结(三)

9Semaphore

Semaphore是并发包中用于控制某个资源访问个数的类,例如数据库的连接池,我们用代码来演示一下一个连接池的实现:

package com.yhj.container.concurrent;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
 
/**
 * @Described:基于信号量的测试用例
 * @author YHJ create at 2012-4-16 下午05:04:53
 * @FileNmae com.yhj.container.concurrent.SemaphoreTestCase.java
 */
public class SemaphoreTestCase {
 
    //连接池
    abstract class Pool{
 
       protected Integer maxActiveConnectionNum;
 
       protected Integer currentActiveConnectionNum;
 
       protected Integer maxWaitTime;
 
       protected List<Connection> pools_used;
 
       protected BlockingQueue<Connection> pools_free;
 
       //构造器
       protected Pool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
           this.maxActiveConnectionNum = maxActiveConnectionNum;
           this.currentActiveConnectionNum = currentActiveConnectionNum;
           this.maxWaitTime = maxWaitTime;
           this.pools_free = new LinkedBlockingQueue<Connection>(maxActiveConnectionNum);
           this.pools_used = new ArrayList<Connection>(maxActiveConnectionNum);
           init();//直接创建最大的容量 本示例未做初始化  不足扩容处理
       }
 
       private void init(){
           for(int i=0;i<maxActiveConnectionNum;++i)
              pools_free.add(new Connection());
       }
 
       //获取连接
       public abstract Connection getConnection();
 
       //关闭连接
       public abstract void closeConnection(Connection connection);
 
    }
 
    //连接供体
    class Connection{
       public Connection() {System.out.println("创建了新的Connection : "+this);}
    }
 
    //普通连接池实现方案
    class NormalPool extends Pool{
 
       protected NormalPool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
           super(maxActiveConnectionNum, currentActiveConnectionNum, maxWaitTime);
       }
 
       @Override
       public Connection 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<maxWaitTime;++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)
                     throw new RuntimeException("Connection timepit with "+maxWaitTime+" milliseconds");
                  else{
                     pools_used.add(connection);
                     System.out.println(Thread.currentThread().getName()+"获取连接"+connection);
                     return connection;
                  }
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
           }
       }
 
       @Override
       public void closeConnection(Connection connection){
 
           synchronized (pools_used) {
              if(pools_used.remove(connection)){
                  pools_free.add(connection);
              }
              System.out.println(Thread.currentThread().getName()+"释放连接"+connection);
              connection = null;
           }
       }
 
    }
 
    //基于信号量的连接池
    class SemaphorePool extends Pool{
 
       private Semaphore semaphore;
 
       protected SemaphorePool(Integer maxActiveConnectionNum,Integer currentActiveConnectionNum, Integer maxWaitTime) {
           super(maxActiveConnectionNum, currentActiveConnectionNum, maxWaitTime);
           semaphore = new Semaphore(maxActiveConnectionNum, true);
       }
 
       @Override
       public Connection getConnection() {
           Connection connection = null;
           try {
              if(semaphore.tryAcquire(maxWaitTime,TimeUnit.MILLISECONDS)){
                  synchronized (pools_free) {
                     connection = pools_free.poll();
                     if(null == connection)
                         throw new RuntimeException("NullPointException in connection free pools");
                     pools_used.add(connection);
                     System.out.println(Thread.currentThread().getName()+"获取连接"+connection);
                     return connection;
                  }
              }else{
                  throw new RuntimeException("Connection timepit with "+maxWaitTime+" milliseconds");
              }
           } catch (InterruptedException e) {
              throw new RuntimeException(e);
           }
       }
 
       @Override
       public void closeConnection(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;
           }
       }
    }
 
    //待执行的任务
    class Task implements Runnable{
 
       private Random random = new Random();
 
       private Pool pool;
      
       public Task(Pool pool) {
           this.pool = pool;
       }
 
       @Override
       public void run() {
           try {
              Connection connection = pool.getConnection();
              Thread.sleep(random.nextInt(1000));
              pool.closeConnection(connection);
           } catch (InterruptedException e) {
           }
 
       }
 
    }
 
    //启动函数
    public void start(){
       int thredCount = 100;
       Pool pool = new NormalPool(10, 10, 100);
       ExecutorService service = Executors.newCachedThreadPool();
       for(int i=0;i<thredCount;++i){
           service.execute(new Task(pool));
       }
       service.shutdown();
       pool = new SemaphorePool(10, 10, 100);
       service = Executors.newCachedThreadPool();
       for(int i=0;i<thredCount;++i){
           service.execute(new Task(pool));
       }
       service.shutdown();
    }
 
    public static void main(String[] args) {
       new SemaphoreTestCase().start();
    }
 
}

运行程序,我们发现如下结果:

很显然,pool-1-thread是第一个线程池的数据,县创建对应的DB连接,然后有很多线程来回去这些连接,随后线程池2进行和创建和分配操作。但是很显然,100ms的超时时间不能承载1~1000ms之间的线程等待,显然中间会产生超时的问题,如下图所示:

同时我们看到中间有连接释放和连接获取的过程。但是拉到最后我们可以看到,pool-2很早就完成了,但是pool1还在执行,如下图所示:

CountDownLatchCyclicBarrier我们在上面的例子中也用到了,分别被用在多线程下做计数器和集合点(其实是另一种计数器),用户控制多线程下的并发操作。而在并罚中还会经常用到的一个锁是ReentrantLockReentrantReadWriteLock。我们分别来看一下:

package com.yhj.container.concurrent;
 
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
 
/**
 * @Described:读写分离的互斥锁 测试用例
 * @author YHJ create at 2012-4-23 下午09:22:53
 * @FileNmae com.yhj.container.concurrent.ReentrantReedWriteLockTestCase.java
 */
public class ReentrantReadWriteLockTestCase {
 
    private Map<String, String> map = new HashMap<String, String>();
 
    private CountDownLatch latch;//计数器
 
    private CyclicBarrier barrier;//集合点
 
    //任务
    abstract class Task implements Runnable{
 
       protected Lock lock;
 
       public Task(Lock lock) {this.lock = lock;}
 
       @Override
       public void run() {
           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();
           }
       }
 
       //真正的业务
       abstract protected void process();
    }
 
    //读任务
    class ReadTask extends Task{
 
       public ReadTask(Lock lock) {super(lock);}
 
       @Override
       protected void process() {
           map.get("test");
       }
    }
    //读任务
    class WriteTask extends Task{
 
       public WriteTask(Lock lock) {super(lock);}
 
       @Override
       protected void process() {
           map.put("test", "case");
       }
    }
 
    //初始化
    private void init(int thredCount){
       latch = new CountDownLatch(thredCount);
       barrier = new CyclicBarrier(thredCount);
    }
   
    //计算耗时
    private void calculateTimeCost(long beginTime){
       try {
           latch.await();
           System.out.println("total time cost "+(System.currentTimeMillis()-beginTime)+" ms");
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
    }
   
    //启动函数
    public void start(){
       int writeThredCount = 100,readThredCount = 400;
       ExecutorService service = Executors.newCachedThreadPool();
       //计算使用ReentrantReadWriteLock耗时
       init(writeThredCount+readThredCount);
       ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
       long beginTime = System.currentTimeMillis();
       for(int i=0;i<writeThredCount;++i)
           service.execute(new WriteTask(reentrantReadWriteLock.writeLock()));
       for(int i=0;i<readThredCount;++i)
           service.execute(new ReadTask(reentrantReadWriteLock.readLock()));
       calculateTimeCost(beginTime);
       //计算使用ReentrantLock的耗时
       init(writeThredCount+readThredCount);
       ReentrantLock reentrantLock = new ReentrantLock();
       beginTime = System.currentTimeMillis();
       for(int i=0;i<writeThredCount;++i)
           service.execute(new WriteTask(reentrantLock));
       for(int i=0;i<readThredCount;++i)
           service.execute(new ReadTask(reentrantLock));
       calculateTimeCost(beginTime);
       service.shutdownNow();
    }
 
    //主函数
    public static void main(String[] args) {
       new ReentrantReadWriteLockTestCase().start();
    }
 
}

我们很清楚的看到,在并发情况下,读写锁分离明显优于一把锁。尤其是在读多写少的环境。

Condition

Condition主要用于控制锁在并发下的唤醒和等待操作,其API说明如下:

以下是官方的一个示例代码,如下所示:

class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition();
   final Condition notEmpty = lock.newCondition();
 
   final Object[] items = new Object[100];
   int putptr, takeptr, count;
 
   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }
 
   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }
 }

以上便是我们实际中可能经常要用到的一些并发包的类,由于时间和精力的原因,在这里也没写那么的详细,当然更多的还是实践,只有实践多了,我们才能更熟练的掌握这些并发相关的知识!

posted @ 2016-02-23 22:18  人生设计师  阅读(878)  评论(0)    收藏  举报