blob: 65785ef13c4cf18e8e37afb11deac7716c41ed29 [file] [log] [blame]
package org.apache.jcs.utils.locking;
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.Hashtable;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jcs.utils.locking.RwLockHolder;
/**
* Used to enhance performance by delaying the removal of unreferenced
* RwLockHolder objects managed by the ReadWriteLockManager.
*
*/
public class RwLockGC extends Thread
{
private final static Log log = LogFactory.getLog( RwLockGC.class );
private final Hashtable ht;
private final static long IDLE_PERIOD = 60 * 1000;
// 60 seconds.
private boolean clean = true;
/**
* Constructor for the RwLockGC object
*
* @param ht
*/
RwLockGC( Hashtable ht )
{
this.ht = ht;
}
/**
* Notifies the garbage collection that there is garbage available, and
* kicks off the garbage collection process.
*/
void notifyGarbage()
{
dirty();
synchronized ( this )
{
notify();
}
}
// Run forever.
// Minimize the use of any synchronization in the process of garbage collection
// for performance reason.
/** Main processing method for the RwLockGC object */
public void run()
{
do
{
if ( clean )
{
synchronized ( this )
{
if ( clean )
{
//p("RwLockGC entering into a wait state");
// Garbage driven mode.
try
{
wait();
// wake up only if there is garbage.
}
catch ( InterruptedException ignore )
{
}
}
}
}
// Time driven mode: sleep between each round of garbage collection.
try
{
//p("RwLockGC sleeping for " + IDLE_PERIOD);
sleep( IDLE_PERIOD );
}
catch ( InterruptedException ex )
{
// ignore;
}
// The "clean" flag must be false here.
// Simply presume we can collect all the garbage until proven otherwise.
synchronized ( this )
{
clean = true;
}
long now = System.currentTimeMillis();
// Take a snapshot of the hashtable.
Map.Entry[] entries = ( Map.Entry[] ) ht.entrySet().toArray( new Map.Entry[0] );
//p("RwLockHolder garbage collecting...");
for ( int i = 0; i < entries.length; i++ )
{
RwLockHolder holder = ( RwLockHolder ) entries[i].getValue();
if ( holder.removable( now ) )
{
Object key = entries[i].getKey();
synchronized ( ht )
{
holder = ( RwLockHolder ) ht.get( key );
// holder cannot possibly be null as this should be the only thread removing them.
if ( holder.removable( now ) )
{
ht.remove( key );
/*
* p("removing key=" + key + ", now=" + now + ", holder.lastInactiveTime="
* + holder.lastInactiveTime);
*/
}
}
}
}
// end for loop.
} while ( true );
}
/** Sets the "clean" flag to false in a critial section. */
private void dirty()
{
if ( clean )
{
synchronized ( this )
{
clean = false;
}
}
}
}