001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.memory;
016    
017    import java.lang.ref.ReferenceQueue;
018    import java.lang.ref.SoftReference;
019    
020    import java.util.Queue;
021    import java.util.concurrent.ConcurrentLinkedQueue;
022    import java.util.concurrent.atomic.AtomicInteger;
023    
024    /**
025     * @author Shuyang Zhou
026     */
027    public class SoftReferencePool<V, P> {
028    
029            public static final int DEFAULT_IDLE_SIZE = 8;
030    
031            public SoftReferencePool(PoolAction<V, P> poolAction) {
032                    this(poolAction, DEFAULT_IDLE_SIZE);
033            }
034    
035            public SoftReferencePool(PoolAction<V, P> poolAction, int maxIdleSize) {
036                    this(poolAction, maxIdleSize, true);
037            }
038    
039            public SoftReferencePool(
040                    PoolAction<V, P> poolAction, int maxIdleSize, boolean useWeakCounter) {
041    
042                    _poolAction = poolAction;
043                    _maxIdleSize = maxIdleSize;
044                    _useWeakCounter = useWeakCounter;
045    
046                    if (_useWeakCounter) {
047                            _weakCounter = new AtomicInteger();
048                    }
049            }
050    
051            public V borrowObject(P parameter) {
052                    while (true) {
053                            SoftReference<? extends V> softReference = _softReferences.poll();
054    
055                            if (softReference == null) {
056                                    return _poolAction.onCreate(parameter);
057                            }
058                            else if (_useWeakCounter) {
059                                    _weakCounter.getAndDecrement();
060                            }
061    
062                            V value = softReference.get();
063    
064                            if (value != null) {
065                                    return _poolAction.onBorrow(value, parameter);
066                            }
067                    }
068            }
069    
070            public void returnObject(V value) {
071                    if (_getCount() < _maxIdleSize) {
072                            SoftReference<V> softReference = new SoftReference<V>(
073                                    value, _referenceQueue);
074    
075                            _poolAction.onReturn(value);
076    
077                            _softReferences.offer(softReference);
078    
079                            if (_useWeakCounter) {
080                                    _weakCounter.getAndIncrement();
081                            }
082                    }
083                    else {
084                            while (_getCount() > _maxIdleSize) {
085                                    if ((_softReferences.poll() != null) && _useWeakCounter) {
086                                            _weakCounter.getAndDecrement();
087                                    }
088                            }
089                    }
090    
091                    SoftReference<? extends V> softReference = null;
092    
093                    while (true) {
094                            softReference = (SoftReference<? extends V>)_referenceQueue.poll();
095    
096                            if (softReference == null) {
097                                    break;
098                            }
099    
100                            if (_softReferences.remove(softReference) && _useWeakCounter) {
101                                    _weakCounter.getAndDecrement();
102                            }
103                    }
104            }
105    
106            private int _getCount() {
107                    if (_useWeakCounter) {
108                            return _weakCounter.get();
109                    }
110                    else {
111                            return _softReferences.size();
112                    }
113            }
114    
115            private int _maxIdleSize;
116            private PoolAction<V, P> _poolAction;
117            private ReferenceQueue<V> _referenceQueue = new ReferenceQueue<V>();
118            private Queue<SoftReference<? extends V>> _softReferences =
119                    new ConcurrentLinkedQueue<SoftReference<? extends V>>();
120            private boolean _useWeakCounter;
121            private AtomicInteger _weakCounter;
122    
123    }