001package net.gdface.utils; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.Collection; 006import java.util.List; 007import java.util.concurrent.LinkedBlockingQueue; 008import java.util.concurrent.atomic.AtomicInteger; 009 010/** 011 * èµ„æºæ± 管ç†å¯¹è±¡<br> 012 * {@link #apply()},{@link #free()}用于申请/释放资æº,申请的资æºå¯¹è±¡ä¸å¯è·¨çº¿ç¨‹è°ƒç”¨,<br> 013 * 通过é‡å†™{@link #isNestable()}方法决定是å¦å…许嵌套调用 014 * @author guyadong 015 * 016 * @param <R> 资æºç±»åž‹ 017 */ 018public class ResourcePool<R>{ 019 /** 资æºé˜Ÿåˆ— */ 020 protected final LinkedBlockingQueue<R> queue = new LinkedBlockingQueue<R>(); 021 /** 当å‰çº¿ç¨‹ç”³è¯·çš„资æºå¯¹è±¡ */ 022 private final ThreadLocal<R> tlsResource = new ThreadLocal<R>(); 023 /** 线程嵌套计数 */ 024 private final ThreadLocal<AtomicInteger> threadNestCount= new ThreadLocal<AtomicInteger>(); 025 private final boolean nestable = isNestable(); 026 protected ResourcePool() { 027 } 028 /** 029 * æž„é€ æ–¹æ³• 030 * @param resources 资æºå¯¹è±¡é›†åˆ 031 * @throws IllegalArgumentException 包å«{@code null}å…ƒç´ 032 */ 033 public ResourcePool(Collection<R> resources){ 034 for(R r:resources){ 035 if(null == r){ 036 throw new IllegalArgumentException("resources contains null element"); 037 } 038 queue.add(r); 039 } 040 } 041 @SafeVarargs 042 public ResourcePool( R ...resources ){ 043 this(Arrays.asList(resources)); 044 } 045 /** 046 * 从资æºé˜Ÿåˆ—{@link #queue}ä¸å–出一个对象,ä¿å˜åˆ°{@link #tlsResource} 047 * @return 048 * @throws InterruptedException 049 */ 050 private R getResource() throws InterruptedException{ 051 if(null != tlsResource.get()){ 052 // 资æºçжæ€å¼‚常 053 throw new IllegalStateException("INVALID tlsResource state"); 054 } 055 R r; 056 if(queue.isEmpty() && null != (r = newResource())){ 057 queue.offer(r); 058 } 059 r = open(queue.take()); 060 tlsResource.set(r); 061 return r; 062 } 063 /** 064 * å°†{@link #tlsResource}ä¸çš„资æºå¯¹è±¡é‡æ–°åŠ å…¥èµ„æºé˜Ÿåˆ—{@link #queue},并清除TLSå˜é‡{@link #tlsResource} 065 */ 066 private void recycleResource(){ 067 R r = tlsResource.get(); 068 if(null == r){ 069 // 资æºçжæ€å¼‚常 070 throw new IllegalStateException("INVALID tlsResource while recycle"); 071 } 072 // 放回队例 073 queue.offer(close(r)); 074 tlsResource.remove(); 075 } 076 /** 077 * (阻塞å¼)申请当å‰çº¿ç¨‹ä½¿ç”¨çš„资æºå¯¹è±¡,ä¸å¯è·¨çº¿ç¨‹ä½¿ç”¨ 078 * @return 079 * @throws InterruptedException 080 */ 081 public final R applyChecked() throws InterruptedException{ 082 if(nestable){ 083 AtomicInteger count = threadNestCount.get(); 084 if(null == count){ 085 // 当å‰çº¿ç¨‹ç¬¬ä¸€æ¬¡ç”³è¯·èµ„æº 086 count = new AtomicInteger(1); 087 threadNestCount.set(count); 088 return getResource(); 089 }else{ 090 // 嵌套调用时直接返回TLSå˜é‡ 091 if(null == this.tlsResource.get()){ 092 // 资æºçжæ€å¼‚常 093 throw new IllegalStateException("INVALID tlsResource"); 094 } 095 count.incrementAndGet(); 096 return this.tlsResource.get(); 097 } 098 }else{ 099 return getResource(); 100 } 101 } 102 /** 103 * (阻塞å¼)申请当å‰çº¿ç¨‹ä½¿ç”¨çš„资æºå¯¹è±¡,ä¸å¯è·¨çº¿ç¨‹ä½¿ç”¨<br> 104 * {@link InterruptedException}å°è£…到{@link RuntimeException}抛出 105 * @return 106 * @see #applyChecked() 107 */ 108 public final R apply(){ 109 try { 110 return applyChecked(); 111 } catch (InterruptedException e) { 112 throw new RuntimeException(e); 113 } 114 } 115 /** 116 * 释放当å‰çº¿ç¨‹å 用的资æºå¯¹è±¡ï¼Œæ”¾å›žèµ„æºé˜Ÿåˆ— 117 */ 118 public final void free(){ 119 if(nestable){ 120 AtomicInteger count = threadNestCount.get(); 121 if(null == count){ 122 // 申请/释放没有æˆå¯¹è°ƒç”¨ 123 throw new IllegalStateException("INVALID nestCount"); 124 } 125 if( 0 == count.decrementAndGet()){ 126 threadNestCount.remove(); 127 recycleResource(); 128 } 129 }else{ 130 recycleResource(); 131 } 132 } 133 /** 是å¦å…许嵌套 */ 134 protected boolean isNestable() { 135 return false; 136 } 137 /** 138 * 创建一个新的资æºå¯¹è±¡ 139 * @return 140 */ 141 protected R newResource(){ 142 return null; 143 } 144 /** 145 * 资æºä»Žé˜Ÿå½¢ä»Žå–出时调用,åç±»å¯é‡å†™æ¤æ–¹æ³• 146 * @param resource 147 * @return 返回 {@code resource 148 */ 149 protected R open(R resource){ 150 return resource; 151 } 152 /** 153 * 资æºå¯¹è±¡æ”¾å›žé˜Ÿåˆ—时调用,åç±»å¯é‡å†™æ¤æ–¹æ³• 154 * @param resource 155 * @return 返回 {@code resource} 156 */ 157 protected R close(R resource){ 158 return resource; 159 } 160 /** 161 * 以固定æ¥é•¿ç”Ÿæˆçš„一组数å—为资æºçš„èµ„æºæ± 对象 162 * @author guyadong 163 * 164 */ 165 public static class IntResourcePool extends ResourcePool<Integer>{ 166 public IntResourcePool(Collection<Integer> resources) { 167 super(resources); 168 } 169 public IntResourcePool(Integer... resources) { 170 super(resources); 171 } 172 /** 173 * æž„é€ æ–¹æ³•<br> 174 * 起始为0,æ¥é•¿ä¸º1 175 * @param capacity 176 * @see #IntResourcePool(int, int, int) 177 */ 178 public IntResourcePool(int capacity){ 179 this(capacity,0, 1); 180 } 181 /** 182 * @param capacity æ•°ç»„å®¹é‡ 183 * @param start èµ·å§‹æ•°å— 184 * @param step æ¥é•¿ 185 * @throws IllegalArgumentException {@code capacity,step}<=0 186 */ 187 public IntResourcePool(int capacity,int start, int step){ 188 this(createList(capacity, start, step)); 189 } 190 /** 191 * ç”¨æŒ‡å®šçš„å‚æ•°æž„é€ ä¸€ä¸ªæ•°å—列表 192 * @param capacity æ•°ç»„å®¹é‡ 193 * @param start èµ·å§‹æ•°å— 194 * @param step æ¥é•¿ 195 * @return 196 */ 197 private static List<Integer> createList(int capacity,int start, int step){ 198 if(capacity <= 0 ){ 199 throw new IllegalArgumentException(String.format("INVALID capacity:%d",capacity)); 200 } 201 if(step <=0 ){ 202 throw new IllegalArgumentException("INVALID step:0"); 203 } 204 ArrayList<Integer> list = new ArrayList<Integer>(capacity); 205 for(int i = start ,endNu= start + capacity*step; i < endNu;i +=step ){ 206 list.add(i); 207 } 208 return list; 209 } 210 } 211}