文档章节

java8 使用Map中的computeIfAbsent方法构建本地缓存,提高程序效率

cloud-coder
 cloud-coder
发布于 2014/04/04 16:01
字数 879
阅读 2613
收藏 31
点赞 1
评论 0

一、概念及使用介绍 

     在JAVA8的Map接口中,增加了一个方法computeIfAbsent,此方法签名如下:

public V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

     Map接口的实现类如HashMap,ConcurrentHashMap,HashTable等继承了此方法,通过此方法可以构建JAVA本地缓存,降低程序的计算量,程序的复杂度,使代码简洁,易懂。

     此方法首先判断缓存MAP中是否存在指定key的值,如果不存在,会自动调用mappingFunction(key)计算key的value,然后将key = value放入到缓存Map,java8会使用thread-safe的方式从cache中存取记录。

    如果mappingFunction(key)返回的值为null或抛出异常,则不会有记录存入map

二 代码样例

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {
	static Map<Integer, Integer> cache = new ConcurrentHashMap<>();

	public static void main(String[] args) throws InterruptedException {
		cache.put(0, 0);
		cache.put(1, 1);
		// 普通方式
		System.out.println("Fibonacci(7) = " + fibonacci(7));
		// 采用java7的同步线程方式及java8的本地缓存的方式
		System.out.println("FibonacciJava8(7) = " + fibonacciJava8(7));
		System.out.println("FibonacciJava7(7) = " + fibonacciJava7(7));

		// 构建多值Map样例代码
		Map<String, HashSet<String>> map1 = new HashMap<>();
		map1.computeIfAbsent("fruits", k -> genValue(k)).add("apple");
		map1.computeIfAbsent("fruits", k -> genValue(k)).add("orange");
		map1.computeIfAbsent("fruits", k -> genValue(k)).add("pear");
		map1.computeIfAbsent("fruits", k -> genValue(k)).add("banana");
		map1.computeIfAbsent("fruits", k -> genValue(k)).add("water");
		System.out.println(map1);

		//测试多线程并发处理,是否同步操作
		Map<String, String> map2 = new ConcurrentHashMap<>();
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			exec.execute(() -> {
				map2.computeIfAbsent("name", k -> genValue2(k));
				map2.computeIfAbsent("addr", k -> genValue2(k));
				map2.computeIfAbsent("email", k -> genValue2(k));
				map2.computeIfAbsent("mobile", k -> genValue2(k));
			});
		}
		exec.shutdown();
		exec.awaitTermination(1, TimeUnit.SECONDS);
		System.out.println(map2);
	}

	static HashSet<String> genValue(String str) {
		return new HashSet<String>();
	}

	static String genValue2(String str) {
		System.out.println("===");
		return str + "2";
	}

	/**
	 * 普通的实现方式 普通方式使用大量的计算,存在性能问题. 并且计算量随着n的增加呈指数级增加,需要用到一些缓存策略,并且是线程安全的.
	 * 
	 * @param n
	 * @return
	 */
	static int fibonacci(int n) {
		if (n == 0 || n == 1)
			return n;

		System.out.println("calculating Fibonacci(" + n + ")");
		return fibonacci(n - 2) + fibonacci(n - 1);
	}

	/**
	 * 采用java8的本地缓存方式 如果缓存MAP中不存在指定key的值,会自动调用mappingFunction(key)计算key的value
	 * 然后将key = value放入到缓存Map,java8会使用thread-safe的方式从cache中存取记录
	 * 
	 * @param n
	 * @return
	 */
	static int fibonacciJava8(int n) {
		return cache.computeIfAbsent(n, (key) -> {
			System.out.println("calculating FibonacciJava8 " + n);
			return fibonacciJava8(n - 2) + fibonacciJava8(n - 1);
		});
	}

	/**
	 * 在java7中的实现方式
	 * 在java7中,通过synchronized进行线程同步,检查缓存是否存在key对应的值,如果不存在才进行计算并放入缓存中
	 * 为了更好的性能,需要使用 double-checked locking,那样代码会更复杂
	 * 
	 * @param n
	 * @return
	 */
	static int fibonacciJava7(int n) {
		if (n == 0 || n == 1)
			return n;

		Integer result = cache.get(n);

		if (result == null) {
			synchronized (cache) {
				result = cache.get(n);

				if (result == null) {
					System.out.println("calculating FibonacciJava7(" + n + ")");
					result = fibonacciJava7(n - 2) + fibonacciJava7(n - 1);
					cache.put(n, result);
				}
			}
		}
		return result;
	}
}

三,程序运行结果

calculating Fibonacci(7)
calculating Fibonacci(5)
calculating Fibonacci(3)
calculating Fibonacci(2)
calculating Fibonacci(4)
calculating Fibonacci(2)
calculating Fibonacci(3)
calculating Fibonacci(2)
calculating Fibonacci(6)
calculating Fibonacci(4)
calculating Fibonacci(2)
calculating Fibonacci(3)
calculating Fibonacci(2)
calculating Fibonacci(5)
calculating Fibonacci(3)
calculating Fibonacci(2)
calculating Fibonacci(4)
calculating Fibonacci(2)
calculating Fibonacci(3)
calculating Fibonacci(2)
Fibonacci(7) = 13
calculating FibonacciJava8 7
calculating FibonacciJava8 5
calculating FibonacciJava8 3
calculating FibonacciJava8 2
calculating FibonacciJava8 4
calculating FibonacciJava8 6
FibonacciJava8(7) = 13
FibonacciJava7(7) = 13
{fruits=[orange, banana, apple, pear, water]}
===
===
===
===
{name=name2, mobile=mobile2, addr=addr2, email=email2}

四、参考

http://www.java8.org/caching-with-ConcurrentHashMap-in-java-8.html

JDK8 API

http://stackoverflow.com/questions/19278443/how-do-i-use-the-new-computeifabsent-function

© 著作权归作者所有

共有 人打赏支持
cloud-coder
粉丝 240
博文 187
码字总数 134554
作品 0
广州
架构师
java8的重要特性及其他,昨天答应的发java8╭(╯ε╰)╮

【注意】本文节选自是 DZone 指南 Java 生态系统的专题文章,作者Trisha Gee是Java资深工程师和布道者。在本文中,Trisha Gee阐述了Java 8的重要特性以及使用的原因,由OneAPM工程师翻译。 ...

默默学习中 ⋅ 2016/03/28 ⋅ 9

为什么选择 Java 8 ?

本文是 DZone 指南 Java 生态系统的专题文章。点击链接可阅读更多见解深刻的文章、行业统计信息,系 OneAPM工程师编译整理。 在很多情况下,Java8 都能提升应用性能,而无需任何改变或性能调...

OneAPM蓝海讯通 ⋅ 2015/11/04 ⋅ 0

LinkedHashMap源码分析-java8

得益于昨天网易的面试,所以重新认识了一个集合,回来后赶紧做了分析,继续努力~ps:面试官真的很nice,希望好运~ 1.特性分析 说明:因为LinkedHashMap单词太长,所以以下都用LHM替代 基本...

caoxiaohong1005 ⋅ 04/12 ⋅ 0

Java8简明指南

Java8简明指南 欢迎来到Java8简明指南。本教程将一步一步指导你通过所有新语言特性。由短而简单的代码示例,带你了解如何使用默认接口方法,lambda表达式,方法引用和可重复注解。本文的最后你会...

王爵nice ⋅ 2015/09/15 ⋅ 2

MapReduce编程之Join多种应用场景与使用

MapReduce编程之Join多种应用场景与使用 Join操作概述 在关系型数据库中 Join 是非常常见的操作,各种优化手段已经到了极致。在海量数据的环境下,不可避免的也会碰到这种类型的需求,例如在...

wypersist ⋅ 05/06 ⋅ 0

缓存那些事儿之【本地缓存篇】

文章摘要:代码调优,SQL调优,DB服务器扩容该做的都做了,接下来该如何优化呢? 一般来说,一个业务平台系统的整体流程可以基本概括为如下图所示,用户请求从UI(浏览器或者客户端)到网络转...

癫狂侠 ⋅ 2017/12/08 ⋅ 0

java8学习笔记

java8学习笔记 拜读了成熟的毛毛虫的java8的文章,收获不小,在此写下阅读笔记。 语法: 和 ObjectReference::methodName 优点: 代码相对简洁,有利于编译器优化代码,提高多核利用率 目的是...

taojinhuo ⋅ 2014/05/31 ⋅ 0

java8新特性介绍

一:接口的默认方法 Java8允许开发者通过使用关键字default向接口中加入非抽象方法。这一特性被称为扩展方法。

yjpfj1203 ⋅ 2016/12/15 ⋅ 0

Spark编程指南

总的来说,每一个Spark应用程序,都是由一个驱动程序组成,它运行用户的main函数,并且在一个集群上执行各种各样的并行操作。Spark提供的主要的抽象(概念)是一个弹性分布式数据集,它是一个...

十一月不远 ⋅ 2014/08/20 ⋅ 1

锐眼洞察 | Java 8 年度实践总结

锐眼洞察 | Java 8 年度实践总结 TalkingData's Blog2018-01-051 阅读 Java 作者:TalkingData架构师 赵志刚 本文为TalkingData原创,未经授权禁止转载。申请授权请在评论中留言联系! Java...

TalkingData's Blog ⋅ 01/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Linux中的端口大全

1 被LANA定义的端口 端口 名称 描述 1 tcpmux TCP 端口服务多路复用 5 rje 远程作业入口 7 echo Echo 服务 9 discard 用于连接测试的空服务 11 systat 用于列举连接了的端口的系统状态 13 d...

寰宇01 ⋅ 14分钟前 ⋅ 0

Confluence 6 如何备份存储文件和页面信息

备份的 ZIP 文件包含有 entities.xml,这个 XML 文件包含有 Confluence 的所有页面内容和存储附件的目录。 备份 Zip 文件结构 页面的附件是存储在附件存储目录中的,通过页面和附件 ID 进行识...

honeymose ⋅ 16分钟前 ⋅ 0

【每天一个JQuery特效】根据状态确定是否滑入或滑出被选元素

主要效果: 本文主要采用slideToggle()方法实现以一行代码同时实现以展开或收缩的方式显示或隐藏被选元素。 主要代码如下: <!DOCTYPE html><html><head><meta charset="UTF-8">...

Rhymo-Wu ⋅ 20分钟前 ⋅ 0

度量.net framework 迁移到.net core的工作量

把现有的.net framework程序迁移到.net core上,是一个非常复杂的工作,特别是一些API在两个平台上还不能同时支持。两个类库的差异性,通过人工很难识别全。好在微软的工程师们考虑到了我们顾...

李朝强 ⋅ 26分钟前 ⋅ 0

请不要在“微服务”的狂热中迷失自我!

微服务在过去几年一直是一个非常热门的话题(附录1)。何为“微服务的疯狂”,举个例子: 众所周知,Netflix在DevOps上的表现非常棒。Netfix可以做微服务。因此:如果我做微服务,我也将非常...

harries ⋅ 27分钟前 ⋅ 0

oAuth2 升级Spring Cloud Finchley.RELEASE踩坑分享

背景 6.19号,spring团队发布了期待已久的 Spring Cloud Finchley.RELEASE 版本。 重要变化: 基于Spring Boot 2.0.X 不兼容 Spring Boot 1.5.X 期间踩过几个坑,分享出来给大伙,主要是关于...

冷冷gg ⋅ 57分钟前 ⋅ 0

OSChina 周一乱弹 —— 理发师小姐姐的魔法

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @冰冰棒- :分享田馥甄的单曲《My Love》 《My Love》- 田馥甄 手机党少年们想听歌,请使劲儿戳(这里) @Li-Wang :哎,头发又长了。。。又要...

小小编辑 ⋅ 今天 ⋅ 8

Kafka1.0.X_消费者API详解2

偏移量由消费者管理 kafka Consumer Api还提供了自己存储offset的功能,将offset和data做到原子性,可以让消费具有Exactly Once 的语义,比kafka默认的At-least Once更强大 消费者从指定分区...

特拉仔 ⋅ 今天 ⋅ 0

NEO智能合约之发布和升级(二)

接NEO智能合约之发布和升级(一),我们接下来说说智能合约的升级功能。 一 准备工作 合约的升级需要在合约内预先设置好升级接口,以方便在升级时调用。接下来我们对NEO智能合约之发布和升级...

红烧飞鱼 ⋅ 今天 ⋅ 0

个人博客的运营模式能否学习TMALL天猫质量为上?

心情随笔|个人博客的运营模式能否学习TMALL天猫质量为上? 中国的互联网已经发展了很多年了,记得在十年前,个人博客十分流行,大量的人都在写博客,而且质量还不错,很多高质量的文章都是在...

原创小博客 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部