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}