net.gdface.utils.ResourcePool Maven / Gradle / Ivy
package net.gdface.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 资源池管理对象
* {@link #apply()},{@link #free()}用于申请/释放资源,申请的资源对象不可跨线程调用,
* 通过重写{@link #isNestable()}方法决定是否允许嵌套调用
* @author guyadong
*
* @param 资源类型
*/
public class ResourcePool{
/** 资源队列 */
protected final LinkedBlockingQueue queue = new LinkedBlockingQueue();
/** 当前线程申请的资源对象 */
private final ThreadLocal tlsResource = new ThreadLocal();
/** 线程嵌套计数 */
private final ThreadLocal threadNestCount= new ThreadLocal();
private final boolean nestable = isNestable();
protected ResourcePool() {
}
/**
* 构造方法
* @param resources 资源对象集合
* @throws IllegalArgumentException 包含{@code null}元素
*/
public ResourcePool(Collection resources){
for(R r:resources){
if(null == r){
throw new IllegalArgumentException("resources contains null element");
}
queue.add(r);
}
}
@SafeVarargs
public ResourcePool( R ...resources ){
this(Arrays.asList(resources));
}
/**
* 从资源队列{@link #queue}中取出一个对象,保存到{@link #tlsResource}
* @return
* @throws InterruptedException
*/
private R getResource() throws InterruptedException{
if(null != tlsResource.get()){
// 资源状态异常
throw new IllegalStateException("INVALID tlsResource state");
}
R r;
if(queue.isEmpty() && null != (r = newResource())){
queue.offer(r);
}
r = open(queue.take());
tlsResource.set(r);
return r;
}
/**
* 将{@link #tlsResource}中的资源对象重新加入资源队列{@link #queue},并清除TLS变量{@link #tlsResource}
*/
private void recycleResource(){
R r = tlsResource.get();
if(null == r){
// 资源状态异常
throw new IllegalStateException("INVALID tlsResource while recycle");
}
// 放回队例
queue.offer(close(r));
tlsResource.remove();
}
/**
* (阻塞式)申请当前线程使用的资源对象,不可跨线程使用
* @return 申请的资源对象
* @throws InterruptedException
*/
public final R applyChecked() throws InterruptedException{
if(nestable){
Integer count = threadNestCount.get();
if(null == count){
// 当前线程第一次申请资源
count = 1;
threadNestCount.set(count);
return getResource();
}else{
// 嵌套调用时直接返回TLS变量
if(null == this.tlsResource.get()){
// 资源状态异常
throw new IllegalStateException("INVALID tlsResource");
}
++ count;
return this.tlsResource.get();
}
}else{
return getResource();
}
}
/**
* (阻塞式)申请当前线程使用的资源对象,不可跨线程使用
* {@link InterruptedException}封装到{@link RuntimeException}抛出
* @return 申请的资源对象
* @see #applyChecked()
*/
public final R apply(){
try {
return applyChecked();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/**
* 释放当前线程占用的资源对象,放回资源队列
*/
public final void free(){
if(nestable){
Integer count = threadNestCount.get();
if(null == count){
// 申请/释放没有成对调用
throw new IllegalStateException("INVALID nestCount");
}
if( 0 == (--count)){
threadNestCount.remove();
recycleResource();
}
}else{
recycleResource();
}
}
/** 是否允许嵌套 */
protected boolean isNestable() {
return false;
}
/**
* 创建一个新的资源对象
* @return 资源对象
*/
protected R newResource(){
return null;
}
/**
* 资源从队形从取出时调用,子类可重写此方法
* @param resource
* @return 返回 {@code resource}
*/
protected R open(R resource){
return resource;
}
/**
* 资源对象放回队列时调用,子类可重写此方法
* @param resource
* @return 返回 {@code resource}
*/
protected R close(R resource){
return resource;
}
/**
* 以固定步长生成的一组数字为资源的资源池对象
* @author guyadong
*
*/
public static class IntResourcePool extends ResourcePool{
public IntResourcePool(Collection resources) {
super(resources);
}
public IntResourcePool(Integer... resources) {
super(resources);
}
/**
* @param capacity 数组容量
* @param start 起始数字
* @param step 步长
* @throws IllegalArgumentException {@code capacity,step}<=0
*/
public IntResourcePool(int capacity,int start, int step){
this(createList(capacity, start, step));
}
/**
* 构造方法
* 起始为0,步长为1
* @param capacity
*/
public IntResourcePool(int capacity){
this(capacity,0, 1);
}
/**
* 用指定的参数构造一个数字列表
* @param capacity 数组容量
* @param start 起始数字
* @param step 步长
* @return
*/
private static List createList(int capacity,int start, int step){
if(capacity <= 0 ){
throw new IllegalArgumentException(String.format("INVALID capacity:%d",capacity));
}
if(step <=0 ){
throw new IllegalArgumentException("INVALID step:0");
}
ArrayList list = new ArrayList(capacity);
for(int i = start ,endNu= start + capacity*step; i < endNu;i +=step ){
list.add(i);
}
return list;
}
}
}