All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.flowcomputing.commons.resgc.ResCollector Maven / Gradle / Ivy

There is a newer version: 0.8.17
Show newest version
package org.flowcomputing.commons.resgc;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Collect resource holders that need to be collected after utilization. It
 * manages to release resource in explicit way and we have change to be notified
 * when its resource is going to be release. In addition, It embedded mechanism
 * to allow resource to be forced release in advance.
 * 
 * @author wg
 *
 * @param 
 *            holder type for any kind of resource.
 * 
 * @param 
 *            resource type to be holden.
 */
public class ResCollector, MRES> implements
		Collector {

	public final static long WAITRECLAIMTIMEOUT = 800;
	public final static long WAITQUEUETIMEOUT = 300;
        public final static long WAITTERMTIMEOUT = 10000;
	public final static long TERMCHECKTIMEOUT = 20;

	private final ReferenceQueue refque = new ReferenceQueue();
	private final Map, MRES> refmap = 
			new ConcurrentHashMap, MRES>();

	private ResReclaim m_reclaimer;
	private Thread m_collector;
	private AtomicLong descnt = new AtomicLong(0L);
	
	private volatile boolean m_stopped = false;

	/**
	 * constructor to accept a resource reclaimer that is used to actual its
	 * resource when needed.
	 * 
	 * @param reclaimer 
	 *          a reclaimer object for managed resource reclaim.
	 */
	public ResCollector(ResReclaim reclaimer) {
		m_reclaimer = reclaimer;
		m_collector = new Thread() {
			public void run() {
				while (!m_stopped) {
					try {
						Reference ref = refque.remove(WAITQUEUETIMEOUT);
                                                if (null != ref) {
							destroyRes(ref);
							descnt.getAndIncrement();
						}
					} catch (InterruptedException ex) {
						break;
					}
				}
			}
		};
		m_collector.setDaemon(true);
		m_collector.start();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.flowcomputing.commons.resgc.Collector#register(org.flowcomputing.
	 * commons.resgc.Holder, java.lang.Object)
	 */
	@Override
	public void register(HOLDER holder) {
		if (null == holder.getRefId()) {
			PhantomReference pref = new PhantomReference(holder,
					refque);
			refmap.put(pref, holder.get());
			holder.setCollector(this);
			holder.setRefId(pref);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.flowcomputing.commons.resgc.Collector#unregister(org.flowcomputing.
	 * commons.resgc.Holder)
	 */
	@Override
	public void unregister(HOLDER holder) {
		if (null != holder.getRefId()) {
			refmap.remove(holder.getRefId());
			holder.setRefId(null);
			holder.setCollector(null);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.flowcomputing.commons.resgc.Collector#removeRef()
	 */
	@Override
	public void removeRef(Reference ref) {
		refmap.remove(ref);
	}

	/**
	 * destroy a specified holden resource.
	 * 
	 * @param ref
	 *            a specified reference that is referring a holder
	 */
	@Override
	public void destroyRes(Reference ref) {
		MRES mres = refmap.remove(ref);
		m_reclaimer.reclaim(mres);
	}

	@Override
	public void destroyRes(MRES mres) {
		m_reclaimer.reclaim(mres);
	}

	private void forceGC(long timeout) {
		System.gc();
		try {
			Thread.sleep(timeout);
		} catch (Exception ex) {
		}
	}

	/**
	 * wait for reclaim termination.
	 *
	 * @param timeout
	 *            specify a timeout to reclaim
	 */
	public void waitReclaimCoolDown(long timeout) {
		do {
			forceGC(timeout);
		} while (0L != descnt.getAndSet(0L));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.flowcomputing.commons.resgc.Collector#close()
	 */
	@Override
	public boolean close(long recltmout, long termtmout) {
		boolean ret = true;
		waitReclaimCoolDown(recltmout);
		m_stopped = true;
		long et = System.currentTimeMillis() + termtmout;
		while (m_collector.getState() != Thread.State.TERMINATED) {
			try {
				Thread.sleep(TERMCHECKTIMEOUT);
			} catch (Exception ex) {
			}
			if (System.currentTimeMillis() > et) {
				ret = false;
				break;
			}
		}
		refmap.clear();
		return ret;
	}

	public boolean close() {
		return close(WAITRECLAIMTIMEOUT, WAITTERMTIMEOUT);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy