/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.memory; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; /** * @author Shuyang Zhou */ public class SoftReferencePool<V, P> { public static final int DEFAULT_IDLE_SIZE = 8; public SoftReferencePool(PoolAction<V, P> poolAction) { this(poolAction, DEFAULT_IDLE_SIZE); } public SoftReferencePool(PoolAction<V, P> poolAction, int maxIdleSize) { this(poolAction, maxIdleSize, true); } public SoftReferencePool( PoolAction<V, P> poolAction, int maxIdleSize, boolean useWeakCounter) { _poolAction = poolAction; _maxIdleSize = maxIdleSize; _useWeakCounter = useWeakCounter; if (_useWeakCounter) { _weakCounter = new AtomicInteger(); } else { _weakCounter = null; } } public V borrowObject(P parameter) { while (true) { SoftReference<? extends V> softReference = _softReferences.poll(); if (softReference == null) { return _poolAction.onCreate(parameter); } else if (_useWeakCounter) { _weakCounter.getAndDecrement(); } V value = softReference.get(); if (value != null) { return _poolAction.onBorrow(value, parameter); } } } public void returnObject(V value) { if (_getCount() < _maxIdleSize) { SoftReference<V> softReference = new SoftReference<>( value, _referenceQueue); _poolAction.onReturn(value); _softReferences.offer(softReference); if (_useWeakCounter) { _weakCounter.getAndIncrement(); } } else { while (_getCount() > _maxIdleSize) { if ((_softReferences.poll() != null) && _useWeakCounter) { _weakCounter.getAndDecrement(); } } } SoftReference<? extends V> softReference = null; while (true) { softReference = (SoftReference<? extends V>)_referenceQueue.poll(); if (softReference == null) { break; } if (_softReferences.remove(softReference) && _useWeakCounter) { _weakCounter.getAndDecrement(); } } } private int _getCount() { if (_useWeakCounter) { return _weakCounter.get(); } else { return _softReferences.size(); } } private final int _maxIdleSize; private final PoolAction<V, P> _poolAction; private final ReferenceQueue<V> _referenceQueue = new ReferenceQueue<>(); private final Queue<SoftReference<? extends V>> _softReferences = new ConcurrentLinkedQueue<>(); private final boolean _useWeakCounter; private final AtomicInteger _weakCounter; }