多线程Lru文件缓存

多线程Lru文件缓存

Posted by candy1126xx on June 16, 2017
public abstract class LruFileCache<K, T> {

	private final LinkedHashMap<String, FileWrapper> lruEntries = new LinkedHashMap<>(0, 0.75f, true);
	private long maxSize = 100;
	
	private File rootFile;
	
	private final Runnable cleanupRunnable = new Runnable() {
		public void run() {
			synchronized (lruEntries) {
				try {
					long curSize = 0;
					Iterator iterator = lruEntries.values().iterator();
					while (curSize < maxSize) {
						FileWrapper file = iterator.next();
						curSize += file.length();
					}
					while (iterator.hasNext()) {
						FileWrapper file = iterator.next();
						file.delete();
						lruEntries.remove(file.name);
					}
				} catch (IOException ignored) {
				}
			}
		}
	};
	
	private final Executor executor = new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS,
		new LinkedBlockingQueue<Runnable>(), 
		new ThreadFactory() {
			@Override public Thread newThread(Runnable runnable) {
				Thread result = new Thread(runnable, name);
				result.setDaemon(true);
				return result;
			}});
	
	public put(K key, T value) {
		String fileName = getFileName(key);
		Editor editor = getEditor(fileName);
		BufferedSink sink = Okio.buffer(editor.newSink());
		sink.writeUtf8(key.toString())
				.writeUtf8(": ")
				.writeUtf8(value.toString())
				.writeByte('\n');
		sink.close();
		executor.execute(cleanupRunnable);
	}
	
	public T get(K key) {
		String fileName = getFileName(key);
		Editor editor = getEditor(fileName);
		BufferedSource source;
		try {
			Source in = editor.newSource();
			source = Okio.buffer(in);
		} finally {
			in.close();
		}
		if (source == null) return null;
		String keyAndValueStr = source.readUtf8LineStrict();
		String valueStr = keyAndValue.subString(keyAndValue.indexOf(": "), keyAndValue.length());
		return T.fromString(valueStr);
	}
	
	private synchronized Editor getEditor(String fileName) throws IOException {
		initialize();
		FileWrapper wrapper = lruEntries.get(fileName);
		if (wrapper != null && wrapper.currentEditor != null)
			return null;
		if (wrapper == null || !wrapper.exists()) {
			wrapper.createNewFile();
			lruEntries.put(fileName, wrapper);
		}
		Editor editor = new Editor(wrapper);
		return editor;
	}
	
	abstract String getFileName(K key);
}
public class Editor {
	private FileWrapper wrapper;

	Editor(FileWrapper wrapper) {
		this.wrapper = wrapper;
	}

	public Source newSource() {
		synchronized (wrapper) {
			if (wrapper.currentEditor != this)
				return null;
			try {
				return Okio.source(file);
			} catch (FileNotFoundException e) {
				return null;
			}
		}
	}

	public Sink newSink() {
		synchronized (wrapper) {
			if (entry.currentEditor != this)
				return Okio.blackhole();
			Sink sink;
			try {
				sink = Okio.sink(file);
			} catch (FileNotFoundException e) {
				return Okio.blackhole();
			}
			return sink;
		}
	}
}