001    /**
002     * Copyright (c) 2000-present 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                    else {
050                            _weakCounter = null;
051                    }
052            }
053    
054            public V borrowObject(P parameter) {
055                    while (true) {
056                            SoftReference<? extends V> softReference = _softReferences.poll();
057    
058                            if (softReference == null) {
059                                    return _poolAction.onCreate(parameter);
060                            }
061                            else if (_useWeakCounter) {
062                                    _weakCounter.getAndDecrement();
063                            }
064    
065                            V value = softReference.get();
066    
067                            if (value != null) {
068                                    return _poolAction.onBorrow(value, parameter);
069                            }
070                    }
071            }
072    
073            public void returnObject(V value) {
074                    if (_getCount() < _maxIdleSize) {
075                            SoftReference<V> softReference = new SoftReference<>(
076                                    value, _referenceQueue);
077    
078                            _poolAction.onReturn(value);
079    
080                            _softReferences.offer(softReference);
081    
082                            if (_useWeakCounter) {
083                                    _weakCounter.getAndIncrement();
084                            }
085                    }
086                    else {
087                            while (_getCount() > _maxIdleSize) {
088                                    if ((_softReferences.poll() != null) && _useWeakCounter) {
089                                            _weakCounter.getAndDecrement();
090                                    }
091                            }
092                    }
093    
094                    SoftReference<? extends V> softReference = null;
095    
096                    while (true) {
097                            softReference = (SoftReference<? extends V>)_referenceQueue.poll();
098    
099                            if (softReference == null) {
100                                    break;
101                            }
102    
103                            if (_softReferences.remove(softReference) && _useWeakCounter) {
104                                    _weakCounter.getAndDecrement();
105                            }
106                    }
107            }
108    
109            private int _getCount() {
110                    if (_useWeakCounter) {
111                            return _weakCounter.get();
112                    }
113                    else {
114                            return _softReferences.size();
115                    }
116            }
117    
118            private final int _maxIdleSize;
119            private final PoolAction<V, P> _poolAction;
120            private final ReferenceQueue<V> _referenceQueue = new ReferenceQueue<>();
121            private final Queue<SoftReference<? extends V>> _softReferences =
122                    new ConcurrentLinkedQueue<>();
123            private final boolean _useWeakCounter;
124            private final AtomicInteger _weakCounter;
125    
126    }