我发布了一个答案here,其中展示使用putIfAbsent
ConcurrentMap
方法的代码为:
ConcurrentMap<String, AtomicLong> map = new ConcurrentHashMap<String, AtomicLong> ();
public long addTo(String key, long value) {
// The final value it became.
long result = value;
// Make a new one to put in the map.
AtomicLong newValue = new AtomicLong(value);
// Insert my new one or get me the old one.
AtomicLong oldValue = map.putIfAbsent(key, newValue);
// Was it already there? Note the deliberate use of '!='.
if ( oldValue != newValue ) {
// Update it.
result = oldValue.addAndGet(value);
}
return result;
}
这种方法的主要缺点是你必须创建一个新的对象来放入地图,无论它是否会被使用。如果对象很重,这可能会产生很大的影响。
我想到这将是一个使用Lambdas的机会。我没有下载Java 8或者我能够直到它是正式的(公司政策)所以我不能测试这个但这样的东西是否有效且有效?
public long addTo(String key, long value) {
return map.putIfAbsent( key, () -> new AtomicLong(0) ).addAndGet(value);
}
我希望使用lambda延迟new AtomicLong(0)
的评估,直到确实应该创建它,因为它在地图中不存在。
正如您所看到的,这更加简洁和实用。
基本上我认为我的问题是:
答案 0 :(得分:7)
更新2015-08-01
如下所述的computeIfAbsent
方法确实是added to Java SE 8。语义似乎非常接近预发布版本。
此外,computeIfAbsent
接口添加了Map
以及一大堆新的默认方法。当然,地图通常不支持原子更新,但新方法为API增加了相当大的便利。
您尝试做的事情是非常合理的,但遗憾的是它不适用于当前版本的ConcurrentMap
。然而,一项改进正在进行中。新版本的并发库包括ConcurrentHashMapV8
,其中包含一个新方法computeIfAbsent
。这几乎可以让你完全按照自己的意愿去做。使用这种新方法,您的示例可以重写如下:
public long addTo(String key, long value) {
return map.computeIfAbsent( key, () -> new AtomicLong(0) ).addAndGet(value);
}
有关ConcurrentHashMapV8
的更多信息,请参阅并发兴趣邮件列表中的Doug Lea的initial announcement thread。线程中的几条消息是a followup message,它显示的示例与您尝试的内容非常相似。 (但请注意旧的lambda语法。该消息毕竟是从2011年8月开始的。)ConcurrentHashMapV8
recent javadoc为{{3}}。
这项工作旨在集成到Java 8中,但我还没有看到它。此外,这仍然是一项正在进行中的工作,名称和规格可能会发生变化等等。
答案 1 :(得分:2)
不幸的是,它并不那么容易。您勾勒出的方法存在两个主要问题:
1.地图的类型需要从Map<String, AtomicLong>
更改为Map<String, AtomicLongFunction>
(其中AtomicLongFunction
是一个函数接口,它具有不带参数的单个方法并返回{{1} })。
2.当您从地图中检索元素时,您需要每次都应用该函数以从中获取AtomicLong
。这会导致每次检索时都创建一个新实例,这可能不是您想要的。
有一个按需运行功能的地图填补缺失值的想法是一个很好的想法,事实上谷歌的Guava库有一张地图可以做到这一点;看他们的MapMaker。事实上,代码将受益于Java 8 lambda表达式:而不是
AtomicLong
你可以写
ConcurrentMap<Key, Graph> graphs = new MapMaker()
.concurrencyLevel(4)
.weakKeys()
.makeComputingMap(
new Function<Key, Graph>() {
public Graph apply(Key key) {
return createExpensiveGraph(key);
}
});
或
ConcurrentMap<Key, Graph> graphs = new MapMaker()
.concurrencyLevel(4)
.weakKeys()
.makeComputingMap((Key key) -> createExpensiveGraph(key));
答案 2 :(得分:2)
AtomicLong
并不是一个重物。对于较重的对象,我会考虑一个惰性代理,并在需要时为该对象提供一个lambda来创建对象。
class MyObject{
void doSomething(){}
}
class MyLazyObject extends MyObject{
Funktion create;
MyLazyObject(Funktion create){
this.create = create;
}
MyObject instance;
MyObject getInstance(){
if(instance == null)
instance = create.apply();
return instance;
}
@Override void doSomething(){getInstance().doSomething();}
}
public long addTo(String key, long value) {
return map.putIfAbsent( key, new MyLazyObject( () -> new MyObject(0) ) );
}
答案 3 :(得分:2)
请注意,使用Java 8 <!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>" />
<meta name="viewport" content="width=device-width, initial scale=1" />
<title><?php wp_title( ' | ', true, 'right' ); ?></title>
<link rel="stylesheet" type="text/css" href="<?php echo get_stylesheet_uri(); ?>" />
<?php wp_head(); ?>
</head>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="<?php echo esc_url( home_url( '/' ) ); ?>">MoonLighting</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="pages/adultanswers.php">Side Job</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">My Account <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Settings</a></li>
<li><a href="#">Add Funds</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Sign Out</a></li>
</ul>
</li>
</ul>
</div>
</div><!-- /.container-fluid -->
</nav>
<body <?php body_class(); ?>>
<div id="wrapper" class="hfeed">
<header id="header" role="banner">
<section id="branding">
<!--I removed this for reasons unrelated-->
</section>
完全没有必要拥有ConcurrentHashMap
值。您可以安全地使用ConcurrentHashMap.merge:
AtomicLong
它更简单,也更快。