`

一个简单的学习多线程缓存的demo

阅读更多
一个简单的学习多线程缓存的demo:
//计算
public interface Computable<A, V> {
	V compute(A arg) throws InterruptedException;
}



/** 第一种最简单实现:采用HashMap,直接在compute()方法上加锁这种构建缓存的方式有很大问题,
 * 如果compute执行时间很长那么有很多线程都要排队等待,那么此时效率可能比没有缓存还低.*/
public class Momizer1<A, V> implements Computable<A, V>{
   
	private final Map<A, V> cacheMap = new HashMap<A, V>();
	private final Computable<A, V> computable;
	public Momizer1(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public synchronized V compute(A arg) throws InterruptedException {
		V v = cacheMap.get(arg);
		if(v==null){
			v = computable.compute(arg);
			cacheMap.put(arg, v);
		}
		
		return v;
	}

}




/** 第二种实现:用ConcurrentHashMap代替HashMap,由于ConcurrentHashMap是线程安全的且效率比较高,所以比第一种效率高.
 * 但是这种方式会产生重复计算问题,假如传入相同的值,因为线程间不知道是否已经开始计算,所以都会去计算。*/
public class Momizer2<A, V> implements Computable<A, V>{
   
	private final ConcurrentHashMap<A, V> cacheMap = new ConcurrentHashMap<A, V>();
	private final Computable<A, V> computable;
	public Momizer2(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public  V compute(A arg) throws InterruptedException {
		V v = cacheMap.get(arg);
		if(v==null){
			v = computable.compute(arg);
			cacheMap.put(arg, v);
		}
		
		return v;
	}

}


/** 第三种实现:将长时间的计算过程用FutureTask替代,如果FutureTask计算结果完毕,那么直接返回结果,
 * 如果没有那么久阻塞等待返回结果.但是这种方式还是没有解决重复计算问题,虽然概率远小于第二种方式.因为
 * 存在符合操作若没有则添加*/
public class Momizer3<A, V> implements Computable<A, V>{
   
	private final ConcurrentHashMap<A, FutureTask<V>> cacheMap = new ConcurrentHashMap<A, FutureTask<V>>();
	private final Computable<A, V> computable;
	public Momizer3(Computable<A, V> computable){
		this.computable = computable;
	}
	@Override
	public  V compute(final A arg) throws InterruptedException {
		FutureTask<V> futureTask = cacheMap.get(arg);
		//
		if(futureTask==null){
			Callable<V> callable = new Callable<V>() {

				@Override
				public V call() throws Exception {
					return computable.compute(arg);
				}
			};
			
			FutureTask<V> f  = new FutureTask<>(callable);
			futureTask = f;
			cacheMap.put(arg, f);
			f.run();
			
			/*futureTask  = new FutureTask<>(callable);
			cacheMap.put(arg, futureTask);
			futureTask.run();*/
		}
		
		try {
			return futureTask.get();
		} catch (ExecutionException e) {
			throw new RuntimeException();
		}
	}

}


/**
 * 第四种实现:利用ConcurrentHashMap的putIfAbsent方法实现,这个方法相当于如果有就返回值,没有就返回null并讲值放入map. 
 */
public class Momizer4<A, V> implements Computable<A, V> {

	private final ConcurrentHashMap<A, FutureTask<V>> cacheMap = new ConcurrentHashMap<A, FutureTask<V>>();
	private final Computable<A, V> computable;

	public Momizer4(Computable<A, V> computable) {
		this.computable = computable;
	}

	@Override
	public V compute(final A arg) throws InterruptedException {
		while(true){
			FutureTask<V> f = cacheMap.get(arg);
			if(f==null){
				Callable<V> callable = new Callable<V>() {

					@Override
					public V call() throws Exception {
						return computable.compute(arg);
					}
					
				};
				FutureTask<V> ft = new FutureTask<>(callable);
				f = cacheMap.putIfAbsent(arg, ft);
				if(f==null){f=ft;ft.run();}
			}
			try {
				return f.get();
			} catch (CancellationException e) {
				//如果FutureTask调用了取消那么清除缓存重新循环放入
				cacheMap.remove(arg);
			}catch (ExecutionException e) {
				e.printStackTrace();
			}
		}

	}

}


分享到:
评论

相关推荐

    C#多线程demo

    - `lock`关键字提供了一种简单的方法来锁定特定对象,确保同一时间只有一个线程可以访问。 - `volatile`关键字用于标记变量,确保所有线程都能看到最新的值,避免缓存导致的问题。 4. **线程池**: - .NET框架中...

    springMVC+多线程+kafka的 demo基于maven

    在本项目中,我们探索了如何将Spring MVC框架与多线程、线程池和Apache Kafka集成,构建一个高效的数据处理系统。以下是关于这些技术及其整合的详细知识点: 1. **Spring MVC**: - Spring MVC是Spring框架的一个...

    多线程图片下载DEMO,不影响文字加载进度

    这个DEMO是一个很好的学习案例,它演示了如何在实际应用中结合多线程、URLSession和表格单元格复用来优化图片加载,提升用户体验。通过分析和理解这个DEMO,开发者可以更好地掌握iOS应用中的异步处理和性能优化技巧...

    Bitmap图片的三级缓存DEMO 三层缓存 强引用 软引用DEMO

    Bitmap图片的三级缓存DEMO是一个典型的应用实例,旨在提高图片加载速度并减少内存消耗。这里我们将深入探讨“三级缓存”、“强引用”和“软引用”这三个核心概念,并通过BitmapUtils三层缓存的实现来阐述它们如何...

    html5离线缓存简单demo

    在这个demo中,我们可以学习如何设置和使用HTML5离线缓存,以及如何结合Web Workers来创建一个离线可用且响应快速的Web应用。通过阅读博客文章(http://blog.csdn.net/mockingbirds/article/details/48412967),...

    构建高效可伸缩的缓存demo

    2. **并发控制**:在多线程环境中,我们需要确保缓存的读写操作是线程安全的。可以使用锁机制,如互斥锁(Mutex)或读写锁(Read-Write Lock),或者使用无锁数据结构,如Java中的ConcurrentHashMap。 3. **分布式...

    ios开发-iOS开发实用demo之多图片多线程下载实例.zip

    在iOS开发中,多图片多线程下载是一个常见的需求,特别是在构建富媒体应用程序时。这个“ios开发-iOS开发实用demo之多图片多线程下载实例”提供了如何在iOS应用中实现这一功能的具体示例。以下是对这个示例中涉及的...

    轻松学会JNI层多线程回调java方法

    总结,学习JNI层多线程回调Java方法,主要涉及以下几点: 1. 理解JNI的基本使用,包括定义和实现native方法。 2. 在多线程环境中正确使用`JNIEnv`,如在新线程中创建新的JNI环境并附加到Java虚拟机。 3. 了解`...

    Android学习中借鉴的多个demo合集

    这个"TestAnything"的Demo可能涵盖了以上提到的某些或全部知识点,每个Demo都是一个具体的应用场景,通过实践这些Demo,开发者可以更好地理解和掌握Android开发的关键技术,从而提升自己的开发能力。同时,作者提醒...

    ASimpleCache缓存框架demo

    ASimpleCache是一个轻量级的缓存框架,旨在简化Android应用中的数据缓存操作。它提供了简单易用的API,让开发者能够快速地在应用程序中集成缓存功能,提高应用性能,减少网络请求,降低服务器压力。这个压缩包包含了...

    多线程样例一 读写参数文件

    读文件费时间,所以开一个线程读文件。 抽象后的类似demo: 假定读文件需要0.6秒,图像处理(用存文件代替)需要0.5秒,各执行100次。 类和函数 读取文件函数: 一,List增加本序号(0开始)。 二,随机生成5000...

    Bitmap高效加载及图片缓存demo

    磁盘缓存则可以存储更多的图片,即使应用关闭后也能快速加载。 6. **异步处理**:图片加载应在后台线程进行,防止UI卡顿。可以使用AsyncTask、Loader或者现代的协程库如Kotlin Coroutines来实现。 7. **内存泄漏...

    一对多锁C++实现和DEMO

    在多线程编程中,确保线程安全是至关重要的,特别是在资源访问方面。"一对多锁"是一种设计模式,用于管理多个线程对共享资源的访问,特别适用于一写多读...学习这个DEMO将有助于理解多线程编程中同步和优化的关键概念。

    安卓listview相关相关-这是一个包含异步加载网络编程JSON解析LruCache图片缓存的简易的ListView图文混排Demo.rar

    这个Demo项目涵盖了多个关键知识点,包括异步加载、网络编程、JSON解析以及LruCache图片缓存策略,这些都是在实际开发中处理数据流和用户体验优化的重要技术。 1. **异步加载**: 在Android中,为了防止UI线程被...

    线程池管理线程demo

    线程池是多线程编程中的一个重要概念,它是一种线程使用模式,旨在优化系统资源的使用并提高系统的响应速度。在Java中,线程池通过`java.util.concurrent`包中的`ExecutorService`接口和其相关类实现。下面将详细...

    android 网络应用轻量框架-多线程管理-高效缓存-设计模式

    6:使用状态模式 观察者模式更好的处理多线程 最初的想法:网络优化开发框架 (移除任务未完成) 网络稳定,系统运行稳定性,大内存消耗稳定,长时间运行稳定性 (旧的系统症结所在) 开启过多线程,导致系统...

    CacheDataTest Demo 缓存

    内存缓存通常使用NSCache类,它是一个轻量级的对象缓存系统,当系统内存不足时,会自动清除部分数据。磁盘缓存则通常使用沙盒中的特定文件夹来存储数据,例如SQLite数据库、文件系统或者使用第三方库如SDWebImage...

    多线程图片加载

    描述中提到“很好用的多线程图片加载,里面有DEMO及Library”,这意味着该项目提供了一个实用的解决方案,并且包含了示例代码(DEMO)以及库文件(Library),开发者可以直接引用和学习。DEMO是演示如何在实际应用中...

    java线程实例 各种小Demo

    1. 继承Thread类:创建一个新的类,继承自Thread类,并重写其run()方法。然后通过创建该类的实例并调用start()方法来启动线程。 2. 实现Runnable接口:创建一个实现了Runnable接口的类,实现run()方法。然后将...

    C#使用Redis缓存示例DEMO asp.net

    接下来,我们将创建一个简单的缓存服务,封装常用的操作: ```csharp public class RedisCacheService { private readonly RedisConnection _connection; public RedisCacheService() { _connection = ...

Global site tag (gtag.js) - Google Analytics