博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程缓存事例
阅读量:5021 次
发布时间:2019-06-12

本文共 3078 字,大约阅读时间需要 10 分钟。

注:文章示例由上而下,安全级别越高。

示例1.

public interface Computable
{ V compute(A arg) throws InterruptedException; } public class ExpensiveFunction implements Computable
{ public BigInteger compute(String arg){ //在经过长时间的计算后 return new BigInteger(arg); } } public class Memoizer1
implements Computable
{ @GuardedBy("this") private final Map
cache = new HashMap
(); private final Computable
c; public Memoizer1(Computable
c){ this.c = c; } public synchronized V compute(A arg) throws InterruptedException{ V result = cache.get(arg); if(result ==null){ result = c.compute(arg); cache.put(arg, result); } return result; } }

 问题是:HashMap 不是线程安全的,因此采用的是将compute方法进行同步。但是这样只能保证每次只有一个线程执行compute方法,有明显的可伸缩性问题。

 

示例2.

public class Memoizer2
implements Computable
{ private final Map
cache = new ConcurrentHashMap
();//线程安全,高效 private final Computable
c; private Memoizer2(Computable
c){ this.c = c; } public V compute(A arg) throws InterruptedException{ V result = cache.get(arg); if(result == null ){ result = c.compute(arg); cache.put(arg,result); } return result; } }

 示例2问题在于:如果某个线程启动了一个开销很大的计算,而其他线程并不知道这个计算正在进行,那么很可能会重复这个计算。

 

示例3.

public class Memoizer3
implements Computable
{ private final Map
> cache = new ConcurrentHashMap
>(); private final Computable
c; private Memoizer3(Computable
c){ this.c = c; } public V compute(final A arg) throws InterruptedException{ Future
f = cache.get(arg);//检查计算是否存在 if(f == null){ Callable
eval = new Callable
(){ public V call() throws InterruptedException{ return c.compute(arg); } }; FutureTask
ft = new FutureTask
(eval);//不存在,创建FutureTask f = ft; cache.put(arg, ft);//注册到map中 ft.run();//开始执行计算 } try { return f.get(); //获得最后计算结果 } catch (ExecutionException e) { } } }

FutureTask :表示一个计算的过程,这个过程可能已经计算完成,也可能正在进行。如果有结果可用,那么FutureTask.get将立即返回结果,否则会一直阻塞,直到结果计算出来再将其返回。

示例3问题在于:仍然存在两个线程重复计算的问题。因为if语句块是复合操作(“若没有则添加”),无法保证原子性。解决这个问题也很简单,只要使用ConcurrentMap 中的原子方法 putIfAbsent就可以啦。

请看示例4

public class Memoizer4
implements Computable
{ private final Map
> cache = new ConcurrentHashMap
>(); private final Computable
c; private Memoizer4(Computable
c){ this.c = c; } public V compute(final A arg) throws InterruptedException{ while(true){ Future
f = cache.get(arg);//检查计算是否存在 if(f == null){ Callable
eval = new Callable
(){ public V call() throws InterruptedException{ return c.compute(arg); } }; FutureTask
ft = new FutureTask
(eval);//不存在,创建FutureTask f = ft; cache.putIfAbsent(arg, ft);//注册到map中, putIfAbsent原子方法 ft.run();//开始执行计算 } try { return f.get(); //获得最后计算结果 } catch (ExecutionException e) { } } } }

 

转载于:https://www.cnblogs.com/cnmenglang/p/6266289.html

你可能感兴趣的文章
Sam做题记录
查看>>
[bzoj] 2453 维护数列 || 单点修改分块
查看>>
IIS版本变迁
查看>>
使用Gzip压缩提升WEB服务器性能
查看>>
BZOJ3884: 上帝与集合的正确用法 拓展欧拉定理
查看>>
mybatis09--自连接一对多查询
查看>>
myeclipse10添加jQuery自动提示的方法
查看>>
【eclipse jar包】在编写java代码时,为方便编程,常常会引用别人已经实现的方法,通常会封装成jar包,我们在编写时,只需引入到Eclipse中即可。...
查看>>
视频监控 封装[PlayCtrl.dll]的API
查看>>
软件工程APP进度更新
查看>>
Python 使用正则替换 re.sub
查看>>
CTF中那些脑洞大开的编码和加密
查看>>
简化工作流程 10款必备的HTML5开发工具
查看>>
c++ 调用外部程序exe-ShellExecuteEx
查看>>
Java进击C#——语法之知识点的改进
查看>>
IdentityServer流程图与相关术语
查看>>
BirdNet: a 3D Object Detection Framework from LiDAR information
查看>>
icon fonts入门
查看>>
【Django】如何按天 小时等查询统计?
查看>>
HDU2191(多重背包)
查看>>