假设我想基于整数id值进行锁定。在这种情况下,有一个函数可从缓存中提取一个值,如果该值不存在,则会进行相当昂贵的检索/存储到缓存中。
现有代码不同步,并且可能触发多个检索/存储操作:
//psuedocode
public Page getPage (Integer id){
Page p = cache.get(id);
if (p==null)
{
p=getFromDataBase(id);
cache.store(p);
}
}
我想做的是同步ID上的检索,例如
if (p==null)
{
synchronized (id)
{
..retrieve, store
}
}
不幸的是,这是行不通的,因为两个单独的调用可以具有相同的Integer id值,但是可以具有不同的Integer对象,因此它们将不会共享锁,并且不会发生同步。
有没有一种简单的方法来确保您拥有相同的Integer实例?例如,这将工作:
syncrhonized (Integer.valueOf(id.intValue())){
Integer.valueOf()的javadoc似乎暗示您很可能会获得相同的实例,但这看起来不像是保证:
返回表示指定int值的Integer实例。如果不需要新的Integer实例,则通常应优先于构造方法Integer(int)使用此方法,因为此方法通过缓存经常请求的值可能会产生明显更好的空间和时间性能。
因此,除了更复杂的解决方案(例如将Lock对象的WeakHashMap保留为int键)以外,还有什么建议可以保证保证Integer实例相同?(这没有错,似乎必须有一个明显的单线而不是我所缺少的)。
你真的不想在上同步Integer
,因为你无法控制哪些实例相同,哪些实例不同。Java只是没有提供跨不同JVM可靠的功能(除非你在较小范围内使用Integers
)。如果确实必须在Integer上进行同步,则需要保留Map或Integer Set,以便可以保证获得所需的确切实例。
最好是创建一个新对象,也许将其存储在以HashMap
键为键的对象中以Integer
进行同步。像这样:
public Page getPage(Integer id) {
Page p = cache.get(id);
if (p == null) {
synchronized (getCacheSyncObject(id)) {
p = getFromDataBase(id);
cache.store(p);
}
}
}
private ConcurrentMap<Integer, Integer> locks = new ConcurrentHashMap<Integer, Integer>();
private Object getCacheSyncObject(final Integer id) {
locks.putIfAbsent(id, id);
return locks.get(id);
}
为了解释该代码,它使用ConcurrentMap
,允许使用putIfAbsent
。你可以这样做:
locks.putIfAbsent(id, new Object());
但随后你需要为每次访问创建一个对象,而这笔费用很小。为避免这种情况,我只将Integer本身保存在中Map。这能达到什么目的?为什么这与仅使用Integer本身有什么不同?
当你get()
从中执行a时Map
,会将键与进行比较equals()
(或至少使用的方法等效于使用equals()
)。具有相同值的两个不同的Integer实例将彼此相等。因此,你可以将“ new Integer(5)”的任意数量的不同Integer实例作为参数传递给getCacheSyncObject你,并且你将始终始终只获取在包含该值的那个实例中传递的第一个实例。
有一些原因可能导致你不希望在Integer...
上进行同步…如果多个线程在Integer
对象上进行同步,从而在它们想要使用不同的锁时不经意地使用相同的锁,则可能会陷入死锁。你可以使用
locks.putIfAbsent(id, new Object());
版本,因此每次访问缓存都会产生(非常小的)成本。这样做,你可以确保此类将在没有其他类进行同步的对象上进行同步。永远是一件好事。
问题内容: 我刚刚遇到了Java中的同步块,并编写了一个小程序来测试它的工作方式。 我创建10个线程,并让每个线程将一个Integer对象增加1000次。 因此,在使用同步的情况下,所有线程完成工作后,我将假定结果为10000,而在没有同步的情况下,结果将小于10000。 但是,同步并没有如我所料。 我猜想这与对象的不变性有关。 我的程序: 有人可以澄清吗? 问题答案: 每次您对 进行同步时,sy
本文向大家介绍java同步与异步的学习笔记整理,包括了java同步与异步的学习笔记整理的使用技巧和注意事项,需要的朋友参考一下 概念: 1、同步:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。 2、异步:将用户请求放入消息队
请看下面给我带来麻烦的方法: 然后是run方法:
Navicat 让你以详细分析的进程从一个数据库和/或模式传输数据到另一个。换句话说,Navicat 给不同的数据库和/或模式的数据提供跟上最新的能力,以便每个库包含相同的信息。你不但能批准回滚传输进程,并且可以插入、删除和更新记录到目标。你可以保存设置成数据同步设置文件用作设置计划。从主菜单选择 工具 -> 数据同步。 全部表必须包含主键和全部表结构在源及目标之间必须相同。你可在数据同步前应用结
问题内容: 这个问题一再被问到,但我仍然有疑问。当人们说同步创建了一个内存障碍时,这个内存障碍适用于什么缓存变量?这看起来不可行。 因此,由于这个疑问,我编写了一些看起来像这样的代码: 我想知道是否有可能只用简单的double []代替total的类型:这将要求synced(总计)(在run()方法中)确保我不使用索引中的每个索引的本地副本双精度数组,即内存围栏不仅适用于自身的值(在指针的背后),
跟进这个问题(Java线程安全-多原子操作?),我不想再增加更多的问题,但现在我有一个疑问: 应该是这样的: 为了保证线程安全。对吗? 所以操作是原子的,但将它们组合起来需要同步,对吗?在这一点上,只使用简单的 HashMap 而不是并发 HashMap 是否有意义,因为我们手动处理同步? CHM中是否有任何方法可以原子地使其工作?