001
014
015 package com.liferay.portal.kernel.util;
016
017 import java.lang.ref.ReferenceQueue;
018 import java.lang.ref.SoftReference;
019
020 import java.util.ArrayList;
021 import java.util.Collections;
022 import java.util.List;
023 import java.util.concurrent.locks.Lock;
024 import java.util.concurrent.locks.ReentrantLock;
025
026
029 public class CharBufferPool {
030
031 public static char[] borrow(int size) {
032 if (!isEnabled()) {
033 return new char[size];
034 }
035
036 _cleanUpDeadBuffers();
037
038 int poolSize = -1;
039
040 _modifyLock.lock();
041
042 try {
043 int index = Collections.binarySearch(
044 _charBufferHoldersPool, new CharBufferHolder(size));
045
046 if (index < 0) {
047 index = -(index + 1);
048 }
049
050 while (index < _charBufferHoldersPool.size()) {
051 CharBufferHolder charBufferHolder = _charBufferHoldersPool.get(
052 index);
053
054 if (charBufferHolder._borrowed) {
055 index++;
056 }
057 else {
058 char[] charBuffer = charBufferHolder.get();
059
060 if (charBuffer != null) {
061 charBufferHolder._borrowed = true;
062
063 List<CharBufferHolder> borrowedCharBufferHolders =
064 _borrowedCharBufferHoldersThreadLocal.get();
065
066 borrowedCharBufferHolders.add(charBufferHolder);
067
068 return charBuffer;
069 }
070
071 _charBufferHoldersPool.remove(index);
072 }
073 }
074 }
075 finally {
076 poolSize = _charBufferHoldersPool.size();
077
078 _modifyLock.unlock();
079 }
080
081 char[] charBuffer = new char[size + (size >> 9)];
082
083 if (poolSize < _MAX_POOL_SIZE) {
084 CharBufferHolder charBufferHolder = new CharBufferHolder(
085 charBuffer);
086
087 List<CharBufferHolder> borrowedCharBufferHolders =
088 _borrowedCharBufferHoldersThreadLocal.get();
089
090 borrowedCharBufferHolders.add(charBufferHolder);
091 }
092
093 return charBuffer;
094 }
095
096 public static void cleanUp() {
097 List<CharBufferHolder> charBufferHolders =
098 _borrowedCharBufferHoldersThreadLocal.get();
099
100 _modifyLock.lock();
101
102 try {
103 for (CharBufferHolder charBufferHolder :
104 charBufferHolders) {
105
106 if (charBufferHolder._borrowed) {
107 charBufferHolder._borrowed = false;
108 }
109 else {
110 int index = Collections.binarySearch(
111 _charBufferHoldersPool, charBufferHolder);
112
113 if (index < 0) {
114 index = -(index + 1);
115 }
116
117 _charBufferHoldersPool.add(index, charBufferHolder);
118 }
119 }
120 }
121 finally {
122 _modifyLock.unlock();
123 }
124
125 charBufferHolders.clear();
126
127 _cleanUpDeadBuffers();
128 }
129
130 public static boolean isEnabled() {
131 return _enabledThreadLocal.get();
132 }
133
134 public static void setEnabled(boolean enabled) {
135 _enabledThreadLocal.set(enabled);
136 }
137
138 private static void _cleanUpDeadBuffers() {
139
140
141
142
143
144
145
146
147
148 CharBufferHolder charBufferHolder =
149 (CharBufferHolder)_referenceQueue.poll();
150
151 if (charBufferHolder == null) {
152 return;
153 }
154
155 _modifyLock.lock();
156
157 try {
158 do {
159 _charBufferHoldersPool.remove(charBufferHolder);
160 }
161 while ((charBufferHolder =
162 (CharBufferHolder)_referenceQueue.poll()) != null);
163 }
164 finally {
165 _modifyLock.unlock();
166 }
167 }
168
169
175 private static final int _INITIAL_POOL_SIZE = 50;
176
177
182 private static final int _MAX_POOL_SIZE = _INITIAL_POOL_SIZE * 2;
183
184 private static ThreadLocal<List<CharBufferHolder>>
185 _borrowedCharBufferHoldersThreadLocal =
186 new AutoResetThreadLocal<List<CharBufferHolder>>(
187 CharBufferPool.class.getName()
188 + "._borrowedCharBufferHoldersThreadLocal",
189 new ArrayList<CharBufferHolder>());
190 private static List<CharBufferHolder> _charBufferHoldersPool =
191 new ArrayList<CharBufferHolder>(_INITIAL_POOL_SIZE);
192 private static ThreadLocal<Boolean> _enabledThreadLocal =
193 new AutoResetThreadLocal<Boolean>(
194 CharBufferPool.class.getName() + "._enabledThreadLocal", false);
195 private static Lock _modifyLock = new ReentrantLock();
196 private static ReferenceQueue<Object> _referenceQueue =
197 new ReferenceQueue<Object>();
198
199 private static class CharBufferHolder
200 extends SoftReference<char[]> implements Comparable<CharBufferHolder> {
201
202 public CharBufferHolder(char[] charBuffer) {
203 super(charBuffer, _referenceQueue);
204
205 _length = charBuffer.length;
206 }
207
208 public CharBufferHolder(int length) {
209 super(null);
210
211 _length = length;
212 }
213
214 public int compareTo(CharBufferHolder charBufferHolder) {
215 return _length - charBufferHolder._length;
216 }
217
218 private boolean _borrowed;
219 private int _length;
220
221 }
222
223 }