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

com.gitee.starblues.loader.classloader.resource.cache.LRUMapCache Maven / Gradle / Ivy

There is a newer version: 3.1.2
Show newest version
/**
 * Copyright [2019-Present] [starBlues]
 *
 * 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.
 */

package com.gitee.starblues.loader.classloader.resource.cache;

import java.util.Iterator;
import java.util.LinkedHashMap;

import java.util.Map;
import java.util.concurrent.locks.StampedLock;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * LRU 缓存实现
 *
 * @author starBlues
 * @since 3.1.1
 * @version 3.1.1
 */
public class LRUMapCache implements Cache{

    private final Map> cacheMap;

    private final StampedLock lock = new StampedLock();

    private final int size;
    private final long timeout;

    public LRUMapCache(int size, long timeout){
        this.size = size;
        this.timeout = timeout;
        this.cacheMap = new CacheLinkedHashMap>(size);
    }

    @Override
    public void put(K key, V value) {
        long stamp = lock.writeLock();
        try {
            Entity entity = new Entity<>(value, timeout);
            if (isFull(key)) {
                cleanExpired(false);
            }
            cacheMap.put(key, entity);
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Override
    public int size() {
        long stamp = lock.tryOptimisticRead();
        int size = cacheMap.size();
        if(!lock.validate(stamp)){
            stamp = lock.readLock();
            try {
                size = cacheMap.size();
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return size;
    }

    @Override
    public boolean containsKey(K key) {
        return get(key) != null;
    }

    @Override
    public V get(K key) {
        long stamp = lock.tryOptimisticRead();
        Entity entity = cacheMap.get(key);
        if(!lock.validate(stamp)){
            stamp = lock.readLock();
            try {
                entity = cacheMap.get(key);
            } finally {
                lock.unlockRead(stamp);
            }
        }
        if(entity != null){
            if(entity.isExpired()){
                remove(key);
                return null;
            }
            return entity.getValue();
        }
        return null;
    }

    @Override
    public V getOrDefault(K key, Supplier supplier, boolean defaultAdded) {
        long stamp = lock.tryOptimisticRead();
        Entity entity = cacheMap.get(key);
        if(!lock.validate(stamp)){
            stamp = lock.readLock();
            try {
                entity = cacheMap.get(key);
            } finally {
                lock.unlockRead(stamp);
            }
        }
        if(entity != null){
            if(entity.isExpired()){
                remove(key);
            } else {
                return entity.getValue();
            }
        }

        V v = supplier.get();
        if(v != null){
            if(defaultAdded){
                put(key, v);
            }
        }
        return v;
    }

    @Override
    public V remove(K key) {
        long stamp = lock.writeLock();
        try {
            Entity cacheValue = cacheMap.remove(key);
            if (cacheValue != null) {
                return cacheValue.getValue();
            } else {
                return null;
            }
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Override
    public void clear() {
        clear(null);
    }

    @Override
    public void clear(Consumer consumer) {
        long stamp = lock.writeLock();
        try {
            if(consumer == null){
                cacheMap.clear();
                return;
            }
            Iterator>> iterator = cacheMap.entrySet().iterator();
            while (iterator.hasNext()){
                try {
                    Map.Entry> entityEntry = iterator.next();
                    Entity value = entityEntry.getValue();
                    if(value == null){
                        iterator.remove();
                        continue;
                    }
                    V v = value.getValue();
                    if(v == null){
                        iterator.remove();
                        continue;
                    }
                    consumer.accept(v);
                } catch (Exception e){
                    // 忽略
                }
            }
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    @Override
    public int cleanExpired() {
        return cleanExpired(true);
    }

    private boolean isFull(K key) {
        if (size == 0) {
            return false;
        }
        if(cacheMap.size() < size){
            return false;
        }
        return !cacheMap.containsKey(key);
    }

    public int cleanExpired(boolean isLock) {
        if(!isLock){
            return actualCleanExpired();
        }
        long stamp = lock.writeLock();
        try {
            return actualCleanExpired();
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    private int actualCleanExpired(){
        Iterator>> cacheMapIterator = cacheMap.entrySet().iterator();
        int removeCount = 0;
        while (cacheMapIterator.hasNext()){
            Map.Entry> entityMap = cacheMapIterator.next();
            Entity value = entityMap.getValue();
            if(value == null || value.isExpired()){
                cacheMapIterator.remove();
                removeCount++;
            }
        }
        return removeCount;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy