宝宝巴士数字世界最新版
113.51 MB · 2025-12-19
null 键/值?约束(Constraints)
成本模型(Cost Model)
最小原语(Primitives)
可验证结论(Check)
Collections.synchronizedMap(new HashMap<>()) 的吞吐差异。null,迭代 fail-fast;并发不安全。null;在高并发下优于全局锁方案。Node<K,V>[] table,桶(bin)冲突时使用 链表,当桶内结点数超过 树化阈值(默认 8) 且容量达到 最小树化容量(默认 64) 时转为 红黑树;当树结点数低于 反树化阈值(默认 6) 时退回链表。(hash = key.hashCode()) ^ (hash >>> 16),减少高位信息丢失导致的桶集中。0.75,在空间与查找冲突率之间折中;阈值 threshold = capacity * loadFactor 触发扩容。null 键与值(null 键固定落在桶 0)。remove)会抛 ConcurrentModificationException。equals/hashCode 契约:不符合将导致查找失败或桶分布异常。equals/hashCode 的字段发生改变,会导致“找不回去”。CAS 初始化 table;桶为空时使用 CAS 放置首节点;桶非空时对桶头节点(或 TreeBin)进行 synchronized 桶级锁 以串行化更新。compute/computeIfAbsent/merge)在桶级锁保护下执行,避免 ABA 与不变量破坏。sizeCtl 控制并发度;出现 ForwardingNode 表示该桶正在迁移,其他线程会 help transfer。ConcurrentModificationException。null 键/值:避免歧义(无法区分“键不存在”与“键存在但值为 null”),也是并发计算方法的前提。size() 可能是近似值(并发下),JDK 8+ 进行了分布式计数;若需要准确性,遍历或使用 mappingCount()(JDK 8 没有该方法,JDK 11+ 提供 mappingCount() 返回 long)。computeIfAbsent 可能成为热点;可引入 分区(striping) 或 分层缓存。forEach 等批处理 API 在大表上可能与迁移竞争,注意任务切分与批量大小。add/remove/set 等写操作会在 独占锁(ReentrantLock) 下复制出 新数组,修改后 原子地替换 引用。CopyOnWriteArrayList 之外的结构(如 ConcurrentHashMap + 有序视图,或 ImmutableList + 引用切换)。import java.util.*;
public class HashMapCollisionDemo {
static class BadKey {
final int id;
BadKey(int id) { this.id = id; }
@Override public int hashCode() { return 42; } // 故意制造高碰撞
@Override public boolean equals(Object o) {
return (o instanceof BadKey) && ((BadKey) o).id == id;
}
}
public static void main(String[] args) {
Map<BadKey, Integer> m = new HashMap<>();
for (int i = 0; i < 100; i++) m.put(new BadKey(i), i);
System.out.println("size=" + m.size());
// 可在调试器中观察桶长度变化与是否树化(需要自行打印内部结构或借助 JFR/可视化)
}
}
import java.util.*;
import java.util.concurrent.*;
public class MapThroughputCompare {
static final int THREADS = 32, OPS = 200_000;
public static void main(String[] args) throws Exception {
compare(new ConcurrentHashMap<>());
compare(Collections.synchronizedMap(new HashMap<>()));
}
static void compare(Map<Integer, Integer> map) throws Exception {
ExecutorService es = Executors.newFixedThreadPool(THREADS);
long t0 = System.nanoTime();
for (int i = 0; i < THREADS; i++) {
es.submit(() -> {
ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int j = 0; j < OPS; j++) {
int k = rnd.nextInt(100_000);
map.put(k, k);
map.get(k);
}
});
}
es.shutdown(); es.awaitTermination(1, TimeUnit.MINUTES);
long t1 = System.nanoTime();
System.out.printf("%s took %.2f ms, size=%d%n", map.getClass().getSimpleName(), (t1 - t0) / 1e6, map.size());
}
}
import java.util.*;
import java.util.concurrent.*;
public class CowalDemo {
public static void main(String[] args) throws Exception {
CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10; i++) list.add(i);
// 迭代快照:下面的写入对本次迭代不可见
for (Integer v : list) {
if (v == 5) list.add(999); // 写时复制,迭代仍遍历旧数组,不抛异常
System.out.print(v + " ");
}
System.out.println("nlist size after add=" + list.size());
}
}
CopyOnWriteArrayList(列表场景)或 ConcurrentHashMap + 定期生成不可变快照(Map 场景)。ConcurrentHashMap,并根据热点键/值进行 分区(striping)、分层缓存 或 批量操作。LinkedHashMap(单线程)或 ConcurrentSkipListMap(并发,按键有序)。List<WeakReference<T>> 或分段结构)降低复制成本。null?
computeIfAbsent 等 API 将出现歧义。null。THREADS/OPS,写结论。add/remove 写入,记录 GC 日志与暂停,评估是否满足你的 SLO;给出替代方案。equals/hashCode 写单元测试;避免可变键。