锁定老帖子 主题:Map 四种同步方式的性能比较
精华帖 (3) :: 良好帖 (18) :: 新手帖 (11) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-02-27
cammette 写道 jsyx 写道 cammette 写道 jsyx 写道 cammette 写道 第一种这样会好点
synchronized(key) { value = map.get(key); } 个人认为,这种写法不是线程安全的 为什么呢? 我们操作map时关注的是key对应的value。 只要我们改变某key的value能同步不就可以了吗? 你总要考虑到写的情况吧。 楼主的测试使用的是HashMap。 在java中,hashmap内部是使用数组来实现的。 无论是put还是get,首先都要根据key的hash值以及数组的长度以及一些其他的常数,计算出一个位置,然后对应get/put,会在这个位置内搜寻或者放置value。当map中存入的对象的个数到了一个临界值时(threshold),hashmap会重新初始化一个新的更长的数组,并且会重新分配所有已存的对象。 public V get(Object key) { Object k = maskNull(key); int hash = hash(k); int i = indexFor(hash, table.length); Entry<K,V> e = table[i]; while (true) { if (e == null) return null; if (e.hash == hash && eq(k, e.key)) return e.value; e = e.next; } } public V put(K key, V value) { K k = maskNull(key); int hash = hash(k); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { if (e.hash == hash && eq(k, e.key)) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, k, value, i); return null; } 举例来说: 如果你只同步key,那么当执行到这一行,以后 int i = indexFor(hash, table.length); 另外一个线程执行了一个新的put操作,导致数组被resize,对象被重新放置。 这样的结果就是你的get操作取不出正确的value或者直接返回null /** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); } 受教了。 不过lz的 synchronized(anObject) { value = map.get(key); } 也会遇到这个问题 synchronized(anObject) { value = map.get(key); } synchronized(anObject) { map.put(key, value); } 这样,我觉得不会有问题,只要保证put和get都同步到这个anObject上来 synchronized(key) { value = map.get(key); } synchronized(key) { map.put(key, value); } 这样会有问题,因为put和get的key可能是不同的对象 |
|
返回顶楼 | |
发表时间:2008-03-05
上面的评论相当的精彩
我请教一下为什么不是 synchronized(map){ value = map.get(key); } |
|
返回顶楼 | |
发表时间:2008-03-08
jomper 写道 上面的评论相当的精彩 我请教一下为什么不是 synchronized(map){ value = map.get(key); } 其实是一样的, synchronized(anObject) { value = map.get(key); } synchronized(map){ value = map.get(key); } 如果anObject只用在map的get和put的同步中,效果是一样的; |
|
返回顶楼 | |
发表时间:2008-04-22
看楼主的图很吓人,synchronized效率这么差啊,jdk1.4的也只能用这个了吧
网上有人建议是说建一个 final static Object lockForMap=new Object(); 然后 synchronized(lockForMap){ value=map.get(key); } 因为synchronized(map)的话,有可能map会被重新实例化,这样子也不保险。 |
|
返回顶楼 | |
发表时间:2009-02-18
jdk1.4可以使用 EDU.oswego.cs.dl.util.concurrent下的
|
|
返回顶楼 | |