併發編程經常使用工具類(二) SymaPhore實現線程池

1.symaPhore簡介

          symaphore(信號量)用來控制同時訪問某個資源的線程數量,通常用在併發流量控制。我的對它的理解至關因而接待室每次只能接待固定數量的人,當達到最高接待數的時候,其餘人就會被攔截在外等待,當前面接待完走出接待室,纔會繼續接待下面的人。數據庫

2.symaphore使用

          symaphore有兩個構造方法:構造方法Semaphore(int permits)接受一個int參數,表示可用的許可證數量,內部默認建立一個非公平鎖;構造方法Semaphore(int permits, boolean fair)接受一個併發

int和一個boolean值,分別表示可用許可證數量和是否使用公平鎖。(公平鎖和非公平鎖後面文章會單獨提到)less

          通常在作流量控制的時候,咱們就能夠經過控制許可證數量來控制併發數的大小,接下來具體聊聊怎麼實現對線程池的控制,代碼以下:dom

 

 1 public class DBPoolSemaphore {
 2     
 3     private final static int POOL_SIZE = 10;
 4     private final Semaphore useful,useless;//useful表示可用的數據庫鏈接,useless表示已用的數據庫鏈接
 5     
 6     public DBPoolSemaphore() {
 7         this. useful = new Semaphore(POOL_SIZE);
 8         this.useless = new Semaphore(0);
 9     }
10     
11     //存放數據庫鏈接的容器
12     private static LinkedList<Connection> pool = new LinkedList<Connection>();
13     //初始化池
14     static {
15         for (int i = 0; i < POOL_SIZE; i++) {
16             pool.addLast(SqlConnectImpl.fetchConnection());
17         }
18     }
19 
20     /*歸還鏈接*/
21     public void returnConnect(Connection connection) throws InterruptedException {
22         if(connection!=null) {
23             System.out.println("當前有"+useful.getQueueLength()+"個線程等待數據庫鏈接!!"
24                     +"可用鏈接數:"+useful.availablePermits());
25             useless.acquire();
26             synchronized (pool) {
27                 pool.addLast(connection);
28             }    
29             useful.release();
30         }
31     }
32     
33     /*從池子拿鏈接*/
34     public Connection takeConnect() throws InterruptedException {
35         useful.acquire();
36         Connection conn;
37         synchronized (pool) {
38             conn = pool.removeFirst();
39         }
40         useless.release();
41         return conn;
42     }
43 }

          首先建立了兩個symaphore對象,分別用來表示已用線程池和可用線程池,在設計拿鏈接和歸還鏈接時,分別前後調用acquire()和release(),acquire()是用來獲取許可,release()歸還許可,至關於在拿鏈接時先去可用鏈接池獲取許可,獲取到纔會繼續執行,不然阻塞等待,直到有鏈接池歸還了鏈接,可用線程許可中能夠獲取到,獲取數據庫鏈接,以後將不可用鏈接許可增長;歸還鏈接恰好相反。本質就是經過控制可用和不可用許可數目,達到控制併發流量的效果。ide

          下面是我設計的一段執行上面代碼的示例:高併發

 1 public class AppTest {
 2 
 3     private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
 4     
 5     //業務線程
 6     private static class BusiThread extends Thread{
 7         @Override
 8         public void run() {
 9             Random r = new Random();//讓每一個線程持有鏈接的時間不同
10             long start = System.currentTimeMillis();
11             try {
12                 Connection connect = dbPool.takeConnect();
13                 System.out.println("Thread_"+Thread.currentThread().getId()
14                         +"_獲取數據庫鏈接共耗時【"+(System.currentTimeMillis()-start)+"】ms.");
15                 SleepTools.ms(100+r.nextInt(100));//模擬業務操做,線程持有鏈接查詢數據
16                 System.out.println("查詢數據完成,歸還鏈接!");
17                 dbPool.returnConnect(connect);
18             } catch (InterruptedException e) {
19             }
20         }
21     }
22     
23     public static void main(String[] args) {
24         for (int i = 0; i < 50; i++) {
25             Thread thread = new BusiThread();
26             thread.start();
27         }
28     }
29     
30 }

          有興趣的同窗可使用上述代碼跑一下,能夠看到前10個線程不耗時間,能夠直接獲取到,後面的會阻塞(花費時間愈來愈長),歸還一個纔會去獲取鏈接,由於個人鏈接許可設置爲10,因此每次最高併發數爲10。fetch

其餘方法

Semaphore還提供一些其餘方法:ui

  • int availablePermits() :返回此信號量中當前可用的許可證數。
  • int getQueueLength():返回正在等待獲取許可證的線程數。
  • boolean hasQueuedThreads() :是否有線程正在等待獲取許可證。
  • void reducePermits(int reduction) :減小reduction個許可證。是個protected方法。
  • Collection getQueuedThreads() :返回全部等待獲取許可證的線程集合。是個protected方法。

 ps:部分引用自http://ifeve.com/concurrency-semaphore/this

相關文章
相關標籤/搜索