A comprehensive, thread-safe cache system implementation in Java with configurable eviction policies, TTL support, and performance monitoring.
This cache system follows modern software design principles and patterns:
- Strategy Pattern: Pluggable eviction policies (FIFO, LRU, LFU)
- Factory Method Pattern: Cache creation with different configurations
- Singleton Pattern: Statistics tracking per cache instance
- Template Method Pattern: Common cache operations structure
- Observer Pattern: Policy notifications for cache events
- ✅ Thread-Safe Operations: Concurrent read/write support using ReadWriteLock
- ✅ Configurable Capacity: Set maximum cache size
- ✅ Multiple Eviction Policies: FIFO, LRU, LFU with pluggable architecture
- ✅ TTL Support: Time-based expiration for cache entries
- ✅ Performance Monitoring: Hit/miss ratios, eviction counts, and detailed statistics
- ✅ Automatic Maintenance: Background cleanup of expired entries
- Evicts the oldest entry based on insertion time
- Suitable for scenarios where temporal locality is important
- Evicts the least recently accessed entry
- Ideal for workloads with temporal access patterns
- Evicts the least frequently accessed entry
- Best for workloads where popularity matters more than recency
- Java 11 or higher
- Maven 3.6 or higher
# Clone and navigate to the project
cd Cache_System
# Compile the project
mvn clean compile
# Run the application
mvn exec:java
# Run with test mode
mvn exec:java -Dexec.args="test"import com.cache.system.core.Cache;
import com.cache.system.factory.CacheFactory;
import com.cache.system.factory.CacheFactory.EvictionPolicyType;
// Create a cache with LRU eviction policy
Cache<String, String> cache = CacheFactory.createCache(100, EvictionPolicyType.LRU);
// Basic operations
cache.put("user:123", "Alice");
Optional<String> user = cache.get("user:123");
cache.remove("user:123");
// TTL operations
cache.put("session:abc", "active", 5000); // 5 second TTL
// Statistics
CacheStats stats = cache.getStats();
System.out.println("Hit rate: " + stats.getHitRate());src/main/java/com/cache/system/
├── core/
│ ├── Cache.java # Cache interface
│ └── CacheImpl.java # Main cache implementation
├── factory/
│ └── CacheFactory.java # Factory for creating cache instances
├── model/
│ ├── CacheEntry.java # Cache entry with metadata
│ └── CacheStats.java # Performance statistics
├── policy/
│ ├── EvictionPolicy.java # Eviction policy interface
│ ├── FIFOEvictionPolicy.java # FIFO implementation
│ ├── LRUEvictionPolicy.java # LRU implementation
│ └── LFUEvictionPolicy.java # LFU implementation
├── test/
│ └── CacheTestSuite.java # Comprehensive test suite
└── Main.java # Demo application and CLI
The project includes a comprehensive test suite that covers:
- ✅ Basic CRUD operations
- ✅ Eviction policy correctness
- ✅ TTL functionality
- ✅ Thread safety under concurrent access
- ✅ Performance and statistics tracking
# Run automated test suite
mvn exec:java -Dexec.args="test"
# Run interactive demo
mvn exec:java| Test Category | Tests | Coverage |
|---|---|---|
| Basic Operations | 6 | Put, Get, Remove, Contains, Size, Clear |
| Eviction Policies | 3 | FIFO, LRU, LFU behavior verification |
| TTL Functionality | 2 | Expiration and persistence |
| Thread Safety | 1 | Concurrent operations |
| Performance | 3 | Statistics, bulk operations, capacity |
The application provides an interactive CLI for testing:
cache> put user:1 Alice
✅ Put 'user:1' -> 'Alice'
cache> get user:1
✅ 'user:1' -> 'Alice'
cache> put session:abc active 5000
✅ Put 'session:abc' -> 'active' (TTL: 5000ms)
cache> stats
📊 CacheStats{hits=1, misses=0, evictions=0, puts=2, hitRate=100.00%}
| Command | Description | Example |
|---|---|---|
put <key> <value> [ttl] |
Add/update entry | put user:1 Alice 5000 |
get <key> |
Retrieve entry | get user:1 |
remove <key> |
Remove entry | remove user:1 |
contains <key> |
Check existence | contains user:1 |
size |
Show cache size | size |
clear |
Clear all entries | clear |
stats |
Show statistics | stats |
list |
List all entries | list |
exit |
Exit interactive mode | exit |
// Using factory with predefined policies
Cache<String, String> lruCache = CacheFactory.createCache(100, EvictionPolicyType.LRU);
Cache<String, String> fifoCache = CacheFactory.createCache(50, EvictionPolicyType.FIFO);
Cache<String, String> lfuCache = CacheFactory.createCache(200, EvictionPolicyType.LFU);
// Using custom eviction policy
EvictionPolicy<String, String> customPolicy = new MyCustomPolicy<>();
Cache<String, String> customCache = CacheFactory.createCache(100, customPolicy);- Capacity: Choose based on available memory and expected data size
- Eviction Policy:
- Use LRU for temporal locality
- Use LFU for frequency-based access
- Use FIFO for simple time-based eviction
- TTL: Set appropriate expiration times for temporary data
The cache implementation provides thread safety through:
- ReadWriteLock: Allows concurrent reads while ensuring exclusive writes
- ConcurrentHashMap: Thread-safe internal storage
- Atomic Operations: For statistics tracking
- Synchronized Methods: For eviction policy operations
// Example: Concurrent access pattern
ExecutorService executor = Executors.newFixedThreadPool(10);
Cache<String, String> cache = CacheFactory.createCache(1000, EvictionPolicyType.LRU);
// Multiple threads can safely access the cache simultaneously
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
cache.put("key" + Thread.currentThread().getId(), "value");
cache.get("key" + Thread.currentThread().getId());
});
}| Operation | Time Complexity | Thread Safety |
|---|---|---|
| Put | O(1) average | ✅ Thread-safe |
| Get | O(1) average | ✅ Thread-safe |
| Remove | O(1) average | ✅ Thread-safe |
| Contains | O(1) average | ✅ Thread-safe |
| Eviction | O(1) - O(n) | ✅ Thread-safe |
- Each cache entry has minimal overhead (key, value, metadata)
- Eviction policies maintain lightweight tracking structures
- Automatic cleanup prevents memory leaks from expired entries
- Single Responsibility: Each class has a single, well-defined purpose
- Open/Closed: Easy to extend with new eviction policies
- Liskov Substitution: All eviction policies are interchangeable
- Interface Segregation: Focused interfaces for different concerns
- Dependency Inversion: Depends on abstractions, not concrete implementations
- Strategy: Eviction policies
- Factory Method: Cache creation
- Template Method: Common cache operations
- Observer: Policy notifications
public class TimeBasedEvictionPolicy<K, V> implements EvictionPolicy<K, V> {
private final Map<K, LocalDateTime> accessTimes = new ConcurrentHashMap<>();
@Override
public void onEntryAccess(CacheEntry<K, V> entry) {
accessTimes.put(entry.getKey(), LocalDateTime.now());
}
@Override
public K selectKeyToEvict() {
return accessTimes.entrySet().stream()
.min(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
}
// Implement other required methods...
}// Create cache with custom policy
EvictionPolicy<String, String> customPolicy = new TimeBasedEvictionPolicy<>();
Cache<String, String> cache = CacheFactory.createCache(100, customPolicy);// Regular statistics monitoring
CacheStats stats = cache.getStats();
logger.info("Cache performance - Hit rate: {}%, Evictions: {}",
stats.getHitRate() * 100, stats.getEvictions());// Ensure proper cleanup
if (cache instanceof CacheImpl) {
((CacheImpl<?, ?>) cache).shutdown();
}- Monitor cache size relative to available heap memory
- Set appropriate TTL for temporary data
- Consider implementing cache warming strategies
- Fork the repository
- Create a feature branch
- Add comprehensive tests
- Follow existing code style and patterns
- Submit a pull request
This project is available under the MIT License.
Built with ❤️ using Java, Maven, and software engineering best practices.