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 : charBufferHolders) {
104 if (charBufferHolder._borrowed) {
105 charBufferHolder._borrowed = false;
106 }
107 else {
108 int index = Collections.binarySearch(
109 _charBufferHoldersPool, charBufferHolder);
110
111 if (index < 0) {
112 index = -(index + 1);
113 }
114
115 _charBufferHoldersPool.add(index, charBufferHolder);
116 }
117 }
118 }
119 finally {
120 _modifyLock.unlock();
121 }
122
123 charBufferHolders.clear();
124
125 _cleanUpDeadBuffers();
126 }
127
128 public static boolean isEnabled() {
129 return _enabledThreadLocal.get();
130 }
131
132 public static void setEnabled(boolean enabled) {
133 _enabledThreadLocal.set(enabled);
134 }
135
136 private static void _cleanUpDeadBuffers() {
137
138
139
140
141
142
143
144
145
146 CharBufferHolder charBufferHolder =
147 (CharBufferHolder)_referenceQueue.poll();
148
149 if (charBufferHolder == null) {
150 return;
151 }
152
153 _modifyLock.lock();
154
155 try {
156 do {
157 _charBufferHoldersPool.remove(charBufferHolder);
158 }
159 while ((charBufferHolder =
160 (CharBufferHolder)_referenceQueue.poll()) != null);
161 }
162 finally {
163 _modifyLock.unlock();
164 }
165 }
166
167
173 private static final int _INITIAL_POOL_SIZE = 50;
174
175
180 private static final int _MAX_POOL_SIZE = _INITIAL_POOL_SIZE * 2;
181
182 private static ThreadLocal<List<CharBufferHolder>>
183 _borrowedCharBufferHoldersThreadLocal =
184 new AutoResetThreadLocal<List<CharBufferHolder>>(
185 CharBufferPool.class.getName() +
186 "._borrowedCharBufferHoldersThreadLocal",
187 new ArrayList<CharBufferHolder>());
188 private static List<CharBufferHolder> _charBufferHoldersPool =
189 new ArrayList<CharBufferHolder>(_INITIAL_POOL_SIZE);
190 private static ThreadLocal<Boolean> _enabledThreadLocal =
191 new AutoResetThreadLocal<Boolean>(
192 CharBufferPool.class.getName() + "._enabledThreadLocal", false);
193 private static Lock _modifyLock = new ReentrantLock();
194 private static ReferenceQueue<Object> _referenceQueue =
195 new ReferenceQueue<Object>();
196
197 private static class CharBufferHolder
198 extends SoftReference<char[]> implements Comparable<CharBufferHolder> {
199
200 public CharBufferHolder(char[] charBuffer) {
201 super(charBuffer, _referenceQueue);
202
203 _length = charBuffer.length;
204 }
205
206 public CharBufferHolder(int length) {
207 super(null);
208
209 _length = length;
210 }
211
212 @Override
213 public int compareTo(CharBufferHolder charBufferHolder) {
214 return _length - charBufferHolder._length;
215 }
216
217 private boolean _borrowed;
218 private int _length;
219
220 }
221
222 }