[{"data":1,"prerenderedAt":2906},["ShallowReactive",2],{"java:java-memory-model\u002F":3,"java-wiki-navigation":1371},{"id":4,"title":5,"body":6,"commentId":1358,"description":1359,"difficulty":1360,"draft":1361,"extension":1362,"meta":1363,"navigation":125,"order":1364,"path":1365,"section":1366,"seo":1367,"stem":1368,"updated":1369,"__hash__":1370},"java\u002Fjava\u002Fjava-memory-model.md","Java 内存模型（JMM）：可见性、有序性与安全发布",{"type":7,"value":8,"toc":1325},"minimark",[9,18,21,27,32,35,80,83,87,90,191,206,209,213,216,225,236,239,261,264,267,270,293,296,302,306,309,316,319,400,403,460,474,478,483,492,495,503,509,524,530,534,615,624,628,633,651,654,709,713,725,772,778,782,789,835,838,857,861,876,885,888,891,894,977,980,983,1020,1027,1045,1052,1056,1063,1137,1140,1155,1158,1161,1181,1190,1193,1196,1199,1205,1208,1212,1215,1219,1226,1230,1236,1240,1243,1247,1250,1253,1258,1261,1300,1303,1321],[10,11,12,13,17],"p",{},"Java 内存模型（Java Memory Model，JMM）描述的是",[14,15,16],"strong",{},"多线程如何正确读写共享变量","。它规定了什么样的执行结果是合法的，以及程序需要通过哪些同步机制建立线程间的可见性与顺序保证。",[10,19,20],{},"一句话概括：",[22,23,24],"blockquote",{},[10,25,26],{},"JMM 解决的不是“数据放在哪里”，而是“一个线程写入的数据，另一个线程何时、以什么顺序能够看到”。",[28,29,31],"h2",{"id":30},"jmm-不是-jvm-运行时内存区域","JMM 不是 JVM 运行时内存区域",[10,33,34],{},"这两个概念名称相似，但关注的问题完全不同。",[36,37,38,54],"table",{},[39,40,41],"thead",{},[42,43,44,48,51],"tr",{},[45,46,47],"th",{},"概念",[45,49,50],{},"关注点",[45,52,53],{},"典型内容",[55,56,57,69],"tbody",{},[42,58,59,63,66],{},[60,61,62],"td",{},"JVM 运行时内存区域",[60,64,65],{},"数据存放在哪里",[60,67,68],{},"堆、虚拟机栈、方法区、程序计数器",[42,70,71,74,77],{},[60,72,73],{},"Java 内存模型 JMM",[60,75,76],{},"多线程如何访问共享数据",[60,78,79],{},"原子性、可见性、有序性、happens-before",[10,81,82],{},"JMM 中的“主内存”和“工作内存”也是规范层面的抽象。可以借助 CPU 缓存、寄存器和编译器临时值来帮助理解，但不能把它们机械地等同于 Java 堆或某一级 CPU Cache。",[28,84,86],{"id":85},"为什么需要-jmm","为什么需要 JMM",[10,88,89],{},"现代 JVM 和处理器会使用缓存、寄存器、指令重排序等手段提高性能。只要单线程结果不变，编译器和 CPU 就可以调整部分操作的执行方式；但在缺少同步的多线程程序中，其他线程可能观察到旧值或不符合源码直觉的顺序。",[91,92,97],"pre",{"className":93,"code":94,"language":95,"meta":96,"style":96},"language-java shiki shiki-themes github-light github-dark","class Switch {\n    private boolean ready = false;\n    private int value = 0;\n\n    void write() {\n        value = 42;\n        ready = true;\n    }\n\n    void read() {\n        if (ready) {\n            System.out.println(value);\n        }\n    }\n}\n","java","",[98,99,100,108,114,120,127,133,139,145,151,156,162,168,174,180,185],"code",{"__ignoreMap":96},[101,102,105],"span",{"class":103,"line":104},"line",1,[101,106,107],{},"class Switch {\n",[101,109,111],{"class":103,"line":110},2,[101,112,113],{},"    private boolean ready = false;\n",[101,115,117],{"class":103,"line":116},3,[101,118,119],{},"    private int value = 0;\n",[101,121,123],{"class":103,"line":122},4,[101,124,126],{"emptyLinePlaceholder":125},true,"\n",[101,128,130],{"class":103,"line":129},5,[101,131,132],{},"    void write() {\n",[101,134,136],{"class":103,"line":135},6,[101,137,138],{},"        value = 42;\n",[101,140,142],{"class":103,"line":141},7,[101,143,144],{},"        ready = true;\n",[101,146,148],{"class":103,"line":147},8,[101,149,150],{},"    }\n",[101,152,154],{"class":103,"line":153},9,[101,155,126],{"emptyLinePlaceholder":125},[101,157,159],{"class":103,"line":158},10,[101,160,161],{},"    void read() {\n",[101,163,165],{"class":103,"line":164},11,[101,166,167],{},"        if (ready) {\n",[101,169,171],{"class":103,"line":170},12,[101,172,173],{},"            System.out.println(value);\n",[101,175,177],{"class":103,"line":176},13,[101,178,179],{},"        }\n",[101,181,183],{"class":103,"line":182},14,[101,184,150],{},[101,186,188],{"class":103,"line":187},15,[101,189,190],{},"}\n",[10,192,193,194,197,198,201,202,205],{},"如果没有任何同步措施，读线程不一定及时看到 ",[98,195,196],{},"ready = true","；即使看到了 ",[98,199,200],{},"ready","，也不能仅凭源码顺序推断它一定看到了 ",[98,203,204],{},"value = 42","。JMM 通过同步动作和 happens-before 规则为这种跨线程通信建立保证。",[28,207,208],{"id":208},"并发正确性的三个维度",[210,211,212],"h3",{"id":212},"原子性",[10,214,215],{},"一个操作不可分割，要么完整执行，要么不执行。",[91,217,219],{"className":93,"code":218,"language":95,"meta":96,"style":96},"count++;\n",[98,220,221],{"__ignoreMap":96},[101,222,223],{"class":103,"line":104},[101,224,218],{},[10,226,227,228,231,232,235],{},"它至少包含读取、加一、写回三个步骤，多个线程并发执行时可能丢失更新。即使把 ",[98,229,230],{},"count"," 声明为 ",[98,233,234],{},"volatile","，也不能让这组复合操作具备原子性。",[10,237,238],{},"常用保证方式包括：",[240,241,242,252,258],"ul",{},[243,244,245,248,249],"li",{},[98,246,247],{},"synchronized"," 或 ",[98,250,251],{},"Lock",[243,253,254,255],{},"CAS 和原子类，如 ",[98,256,257],{},"AtomicInteger",[243,259,260],{},"将共享状态封装到线程安全的数据结构中",[210,262,263],{"id":263},"可见性",[10,265,266],{},"一个线程修改共享变量后，其他线程能否及时看到修改结果。",[10,268,269],{},"常见的可见性保证来自：",[240,271,272,277,280,290],{},[243,273,274,276],{},[98,275,234],{}," 读写",[243,278,279],{},"同一把锁的释放和获取",[243,281,282,285,286,289],{},[98,283,284],{},"Thread.start()","、",[98,287,288],{},"Thread.join()"," 等线程生命周期规则",[243,291,292],{},"并发容器和线程安全队列提供的内存一致性语义",[210,294,295],{"id":295},"有序性",[10,297,298,299,301],{},"编译器和处理器可以在不改变单线程结果的前提下重排序，这就是 as-if-serial 语义。并发程序需要通过 ",[98,300,234],{},"、锁等机制约束那些会影响跨线程观察结果的重排序。",[28,303,305],{"id":304},"happens-before判断可见性的核心规则","happens-before：判断可见性的核心规则",[10,307,308],{},"如果操作 A happens-before 操作 B，那么 A 的结果必须对 B 可见，并且 JMM 保证 A 在 B 之前有序。",[10,310,311,312,315],{},"它是一种",[14,313,314],{},"内存可见性和顺序保证","，不应简单理解成现实时间上的“先发生”。",[10,317,318],{},"常见规则如下：",[36,320,321,331],{},[39,322,323],{},[42,324,325,328],{},[45,326,327],{},"规则",[45,329,330],{},"含义",[55,332,333,341,349,357,369,381,392],{},[42,334,335,338],{},[60,336,337],{},"程序次序规则",[60,339,340],{},"单线程内，按程序顺序位于前面的操作 happens-before 后面的操作",[42,342,343,346],{},[60,344,345],{},"监视器锁规则",[60,347,348],{},"对一把锁的解锁 happens-before 后续对同一把锁的加锁",[42,350,351,354],{},[60,352,353],{},"volatile 规则",[60,355,356],{},"对一个 volatile 变量的写 happens-before 后续对它的读",[42,358,359,362],{},[60,360,361],{},"线程启动规则",[60,363,364,365,368],{},"调用 ",[98,366,367],{},"start()"," 前的操作 happens-before 新线程中的操作",[42,370,371,374],{},[60,372,373],{},"线程终止规则",[60,375,376,377,380],{},"线程内的操作 happens-before 其他线程从 ",[98,378,379],{},"join()"," 成功返回",[42,382,383,386],{},[60,384,385],{},"中断规则",[60,387,364,388,391],{},[98,389,390],{},"interrupt()"," happens-before 目标线程检测到中断",[42,393,394,397],{},[60,395,396],{},"传递性",[60,398,399],{},"A happens-before B，B happens-before C，则 A happens-before C",[10,401,402],{},"例如：",[91,404,406],{"className":93,"code":405,"language":95,"meta":96,"style":96},"int data = 0;\nvolatile boolean ready = false;\n\n\u002F\u002F 线程 A\ndata = 42;\nready = true;\n\n\u002F\u002F 线程 B\nif (ready) {\n    System.out.println(data); \u002F\u002F 能看到 42\n}\n",[98,407,408,413,418,422,427,432,437,441,446,451,456],{"__ignoreMap":96},[101,409,410],{"class":103,"line":104},[101,411,412],{},"int data = 0;\n",[101,414,415],{"class":103,"line":110},[101,416,417],{},"volatile boolean ready = false;\n",[101,419,420],{"class":103,"line":116},[101,421,126],{"emptyLinePlaceholder":125},[101,423,424],{"class":103,"line":122},[101,425,426],{},"\u002F\u002F 线程 A\n",[101,428,429],{"class":103,"line":129},[101,430,431],{},"data = 42;\n",[101,433,434],{"class":103,"line":135},[101,435,436],{},"ready = true;\n",[101,438,439],{"class":103,"line":141},[101,440,126],{"emptyLinePlaceholder":125},[101,442,443],{"class":103,"line":147},[101,444,445],{},"\u002F\u002F 线程 B\n",[101,447,448],{"class":103,"line":153},[101,449,450],{},"if (ready) {\n",[101,452,453],{"class":103,"line":158},[101,454,455],{},"    System.out.println(data); \u002F\u002F 能看到 42\n",[101,457,458],{"class":103,"line":164},[101,459,190],{},[10,461,462,465,466,469,470,473],{},[98,463,464],{},"data = 42"," 位于 volatile 写之前；线程 B 读取到 ",[98,467,468],{},"ready == true"," 后，借助程序次序、volatile 规则和传递性，也能看到此前对 ",[98,471,472],{},"data"," 的写入。",[28,475,477],{"id":476},"volatile-的能力与边界","volatile 的能力与边界",[10,479,480,482],{},[98,481,234],{}," 主要提供两类保证：",[484,485,486,489],"ol",{},[243,487,488],{},"对该变量的写入能够被后续读取它的线程看到。",[243,490,491],{},"禁止影响发布与读取语义的特定重排序。",[10,493,494],{},"可以将它理解为写端的 release 和读端的 acquire：",[91,496,501],{"className":497,"code":499,"language":500,"meta":96},[498],"language-text","线程 A 的普通写\n       ↓\nvolatile 写（发布）\n       ↓ happens-before\nvolatile 读（获取）\n       ↓\n线程 B 的普通读\n","text",[98,502,499],{"__ignoreMap":96},[10,504,505,506,508],{},"但 ",[98,507,234],{}," 不提供复合操作的互斥性：",[91,510,512],{"className":93,"code":511,"language":95,"meta":96,"style":96},"volatile int count = 0;\ncount++; \u002F\u002F 仍然不是线程安全的\n",[98,513,514,519],{"__ignoreMap":96},[101,515,516],{"class":103,"line":104},[101,517,518],{},"volatile int count = 0;\n",[101,520,521],{"class":103,"line":110},[101,522,523],{},"count++; \u002F\u002F 仍然不是线程安全的\n",[10,525,526,527,529],{},"适合 ",[98,528,234],{}," 的典型场景是状态标志、不可变快照的引用和读多写少的整体配置切换。",[210,531,533],{"id":532},"dcl-单例为什么需要-volatile","DCL 单例为什么需要 volatile",[91,535,537],{"className":93,"code":536,"language":95,"meta":96,"style":96},"public final class Singleton {\n    private static volatile Singleton instance;\n\n    private Singleton() {}\n\n    public static Singleton getInstance() {\n        if (instance == null) {\n            synchronized (Singleton.class) {\n                if (instance == null) {\n                    instance = new Singleton();\n                }\n            }\n        }\n        return instance;\n    }\n}\n",[98,538,539,544,549,553,558,562,567,572,577,582,587,592,597,601,606,610],{"__ignoreMap":96},[101,540,541],{"class":103,"line":104},[101,542,543],{},"public final class Singleton {\n",[101,545,546],{"class":103,"line":110},[101,547,548],{},"    private static volatile Singleton instance;\n",[101,550,551],{"class":103,"line":116},[101,552,126],{"emptyLinePlaceholder":125},[101,554,555],{"class":103,"line":122},[101,556,557],{},"    private Singleton() {}\n",[101,559,560],{"class":103,"line":129},[101,561,126],{"emptyLinePlaceholder":125},[101,563,564],{"class":103,"line":135},[101,565,566],{},"    public static Singleton getInstance() {\n",[101,568,569],{"class":103,"line":141},[101,570,571],{},"        if (instance == null) {\n",[101,573,574],{"class":103,"line":147},[101,575,576],{},"            synchronized (Singleton.class) {\n",[101,578,579],{"class":103,"line":153},[101,580,581],{},"                if (instance == null) {\n",[101,583,584],{"class":103,"line":158},[101,585,586],{},"                    instance = new Singleton();\n",[101,588,589],{"class":103,"line":164},[101,590,591],{},"                }\n",[101,593,594],{"class":103,"line":170},[101,595,596],{},"            }\n",[101,598,599],{"class":103,"line":176},[101,600,179],{},[101,602,603],{"class":103,"line":182},[101,604,605],{},"        return instance;\n",[101,607,608],{"class":103,"line":187},[101,609,150],{},[101,611,613],{"class":103,"line":612},16,[101,614,190],{},[10,616,617,618,620,621,623],{},"对象创建可以近似看作分配内存、初始化对象、赋值引用。缺少 ",[98,619,234],{}," 时，引用赋值可能被其他线程观察到，而对象初始化结果尚未通过正确的同步关系对它可见。",[98,622,234],{}," 既限制关键重排序，也安全发布了构造完成的引用。",[28,625,627],{"id":626},"synchronized-提供什么保证","synchronized 提供什么保证",[10,629,630,632],{},[98,631,247],{}," 同时提供：",[240,634,635,640,645],{},[243,636,637,639],{},[14,638,212],{},"：同一时刻只有持有同一把锁的线程进入临界区。",[243,641,642,644],{},[14,643,263],{},"：前一个线程解锁前的写入，对后续获得同一把锁的线程可见。",[243,646,647,650],{},[14,648,649],{},"必要的有序性","：锁边界限制会破坏同步语义的重排序。",[10,652,653],{},"对比来看：",[36,655,656,667],{},[39,657,658],{},[42,659,660,663,665],{},[45,661,662],{},"能力",[45,664,234],{},[45,666,247],{},[55,668,669,678,687,698],{},[42,670,671,673,676],{},[60,672,263],{},[60,674,675],{},"保证",[60,677,675],{},[42,679,680,683,685],{},[60,681,682],{},"特定有序性",[60,684,675],{},[60,686,675],{},[42,688,689,692,695],{},[60,690,691],{},"复合操作原子性",[60,693,694],{},"不保证",[60,696,697],{},"保证临界区内的原子性",[42,699,700,703,706],{},[60,701,702],{},"竞争时是否阻塞",[60,704,705],{},"不阻塞",[60,707,708],{},"可能阻塞",[28,710,712],{"id":711},"final-字段的内存语义","final 字段的内存语义",[10,714,715,718,719,721,722,724],{},[98,716,717],{},"final"," 不只是“赋值后不能修改”。JMM 还为正确构造对象的 ",[98,720,717],{}," 字段提供特殊初始化保证：构造器中对 ",[98,723,717],{}," 字段的写入，不能被重排到对象引用发布之后。",[91,726,728],{"className":93,"code":727,"language":95,"meta":96,"style":96},"final class Config {\n    private final int timeout;\n    private final String endpoint;\n\n    Config(int timeout, String endpoint) {\n        this.timeout = timeout;\n        this.endpoint = endpoint;\n    }\n}\n",[98,729,730,735,740,745,749,754,759,764,768],{"__ignoreMap":96},[101,731,732],{"class":103,"line":104},[101,733,734],{},"final class Config {\n",[101,736,737],{"class":103,"line":110},[101,738,739],{},"    private final int timeout;\n",[101,741,742],{"class":103,"line":116},[101,743,744],{},"    private final String endpoint;\n",[101,746,747],{"class":103,"line":122},[101,748,126],{"emptyLinePlaceholder":125},[101,750,751],{"class":103,"line":129},[101,752,753],{},"    Config(int timeout, String endpoint) {\n",[101,755,756],{"class":103,"line":135},[101,757,758],{},"        this.timeout = timeout;\n",[101,760,761],{"class":103,"line":141},[101,762,763],{},"        this.endpoint = endpoint;\n",[101,765,766],{"class":103,"line":147},[101,767,150],{},[101,769,770],{"class":103,"line":153},[101,771,190],{},[10,773,774,775,777],{},"只要对象在构造过程中没有逸出，其他线程获得该对象后，能看到 ",[98,776,717],{}," 字段的正确初始化值。",[210,779,781],{"id":780},"构造期间不要让-this-逸出","构造期间不要让 this 逸出",[10,783,784,785,788],{},"下面的写法会在对象尚未构造完成时把 ",[98,786,787],{},"this"," 暴露出去：",[91,790,792],{"className":93,"code":791,"language":95,"meta":96,"style":96},"class Listener {\n    static Listener shared;\n    final int value;\n\n    Listener() {\n        shared = this; \u002F\u002F this 提前逸出\n        value = 42;\n    }\n}\n",[98,793,794,799,804,809,813,818,823,827,831],{"__ignoreMap":96},[101,795,796],{"class":103,"line":104},[101,797,798],{},"class Listener {\n",[101,800,801],{"class":103,"line":110},[101,802,803],{},"    static Listener shared;\n",[101,805,806],{"class":103,"line":116},[101,807,808],{},"    final int value;\n",[101,810,811],{"class":103,"line":122},[101,812,126],{"emptyLinePlaceholder":125},[101,814,815],{"class":103,"line":129},[101,816,817],{},"    Listener() {\n",[101,819,820],{"class":103,"line":135},[101,821,822],{},"        shared = this; \u002F\u002F this 提前逸出\n",[101,824,825],{"class":103,"line":141},[101,826,138],{},[101,828,829],{"class":103,"line":147},[101,830,150],{},[101,832,833],{"class":103,"line":153},[101,834,190],{},[10,836,837],{},"常见的构造期间逸出还包括：",[240,839,840,845,848,854],{},[243,841,842,843],{},"在构造器中注册监听器并传入 ",[98,844,787],{},[243,846,847],{},"在构造器中启动访问当前对象的新线程",[243,849,850,851,853],{},"把 ",[98,852,787],{}," 放入静态集合或共享容器",[243,855,856],{},"在构造器中调用可能被子类重写并暴露状态的方法",[210,858,860],{"id":859},"final-引用不等于对象不可变","final 引用不等于对象不可变",[91,862,864],{"className":93,"code":863,"language":95,"meta":96,"style":96},"final List\u003CString> names = new ArrayList\u003C>();\nnames.add(\"Alice\"); \u002F\u002F 合法\n",[98,865,866,871],{"__ignoreMap":96},[101,867,868],{"class":103,"line":104},[101,869,870],{},"final List\u003CString> names = new ArrayList\u003C>();\n",[101,872,873],{"class":103,"line":110},[101,874,875],{},"names.add(\"Alice\"); \u002F\u002F 合法\n",[10,877,878,880,881,884],{},[98,879,717],{}," 只保证 ",[98,882,883],{},"names"," 不能重新指向另一个 List，并不保证 List 内部状态不可修改，更不保证多个线程并发修改安全。构建不可变对象还需要避免修改入口，并对可变集合进行防御性复制。",[28,886,887],{"id":887},"什么是安全发布",[10,889,890],{},"安全发布是指：一个线程创建对象后，通过明确的同步机制把它交给其他线程，使其他线程既能看到对象引用，也能看到对象完整初始化后的状态。",[10,892,893],{},"常见方式包括：",[36,895,896,909],{},[39,897,898],{},[42,899,900,903,906],{},[45,901,902],{},"方式",[45,904,905],{},"建立保证的原因",[45,907,908],{},"适用场景",[55,910,911,922,933,944,955,966],{},[42,912,913,916,919],{},[60,914,915],{},"静态初始化",[60,917,918],{},"JVM 保证类初始化串行完成，并对后续使用可见",[60,920,921],{},"固定单例、常量配置",[42,923,924,927,930],{},[60,925,926],{},"volatile 引用",[60,928,929],{},"volatile 写 happens-before 后续读",[60,931,932],{},"配置热更新、不可变快照切换",[42,934,935,938,941],{},[60,936,937],{},"synchronized \u002F Lock",[60,939,940],{},"同一把锁的释放 happens-before 后续获取",[60,942,943],{},"对象发布并伴随复合读写",[42,945,946,949,952],{},[60,947,948],{},"并发容器",[60,950,951],{},"容器操作提供相应的内存一致性保证",[60,953,954],{},"跨线程共享和查找对象",[42,956,957,960,963],{},[60,958,959],{},"BlockingQueue",[60,961,962],{},"入队前的操作对成功出队后的线程可见",[60,964,965],{},"生产者—消费者",[42,967,968,971,974],{},[60,969,970],{},"AtomicReference",[60,972,973],{},"volatile 语义加 CAS",[60,975,976],{},"需要条件更新的对象快照",[210,978,979],{"id":979},"静态字段不等于静态初始化",[10,981,982],{},"下面只是运行期间对共享静态字段的一次普通写入，并不天然安全：",[91,984,986],{"className":93,"code":985,"language":95,"meta":96,"style":96},"class ConfigHolder {\n    static Config config;\n\n    static void init() {\n        config = new Config();\n    }\n}\n",[98,987,988,993,998,1002,1007,1012,1016],{"__ignoreMap":96},[101,989,990],{"class":103,"line":104},[101,991,992],{},"class ConfigHolder {\n",[101,994,995],{"class":103,"line":110},[101,996,997],{},"    static Config config;\n",[101,999,1000],{"class":103,"line":116},[101,1001,126],{"emptyLinePlaceholder":125},[101,1003,1004],{"class":103,"line":122},[101,1005,1006],{},"    static void init() {\n",[101,1008,1009],{"class":103,"line":129},[101,1010,1011],{},"        config = new Config();\n",[101,1013,1014],{"class":103,"line":135},[101,1015,150],{},[101,1017,1018],{"class":103,"line":141},[101,1019,190],{},[10,1021,1022,1023,1026],{},"真正依赖 JVM 类初始化进行安全发布的是字段初始化表达式或 ",[98,1024,1025],{},"static"," 代码块：",[91,1028,1030],{"className":93,"code":1029,"language":95,"meta":96,"style":96},"class ConfigHolder {\n    static final Config CONFIG = new Config();\n}\n",[98,1031,1032,1036,1041],{"__ignoreMap":96},[101,1033,1034],{"class":103,"line":104},[101,1035,992],{},[101,1037,1038],{"class":103,"line":110},[101,1039,1040],{},"    static final Config CONFIG = new Config();\n",[101,1042,1043],{"class":103,"line":116},[101,1044,190],{},[10,1046,1047,1048,1051],{},"二者的区别不在于“字段是否为 static”，而在于赋值是否发生在 JVM 的类初始化方法 ",[98,1049,1050],{},"\u003Cclinit>"," 中。",[28,1053,1055],{"id":1054},"volatile-动态发布构造后整体替换","volatile 动态发布：构造后整体替换",[10,1057,1058,1059,1062],{},"对于运行期配置更新，一个实用模式是：",[14,1060,1061],{},"先完整构造不可变对象，最后一步写入 volatile 引用","。",[91,1064,1066],{"className":93,"code":1065,"language":95,"meta":96,"style":96},"public final class ConfigCenter {\n    private static volatile Config current =\n            new Config(3000, 2);\n\n    public static Config current() {\n        return current;\n    }\n\n    public static void reload(int timeout, int retries) {\n        Config next = new Config(timeout, retries);\n        current = next; \u002F\u002F 最后一步发布\n    }\n\n    public record Config(int timeout, int retries) {}\n}\n",[98,1067,1068,1073,1078,1083,1087,1092,1097,1101,1105,1110,1115,1120,1124,1128,1133],{"__ignoreMap":96},[101,1069,1070],{"class":103,"line":104},[101,1071,1072],{},"public final class ConfigCenter {\n",[101,1074,1075],{"class":103,"line":110},[101,1076,1077],{},"    private static volatile Config current =\n",[101,1079,1080],{"class":103,"line":116},[101,1081,1082],{},"            new Config(3000, 2);\n",[101,1084,1085],{"class":103,"line":122},[101,1086,126],{"emptyLinePlaceholder":125},[101,1088,1089],{"class":103,"line":129},[101,1090,1091],{},"    public static Config current() {\n",[101,1093,1094],{"class":103,"line":135},[101,1095,1096],{},"        return current;\n",[101,1098,1099],{"class":103,"line":141},[101,1100,150],{},[101,1102,1103],{"class":103,"line":147},[101,1104,126],{"emptyLinePlaceholder":125},[101,1106,1107],{"class":103,"line":153},[101,1108,1109],{},"    public static void reload(int timeout, int retries) {\n",[101,1111,1112],{"class":103,"line":158},[101,1113,1114],{},"        Config next = new Config(timeout, retries);\n",[101,1116,1117],{"class":103,"line":164},[101,1118,1119],{},"        current = next; \u002F\u002F 最后一步发布\n",[101,1121,1122],{"class":103,"line":170},[101,1123,150],{},[101,1125,1126],{"class":103,"line":176},[101,1127,126],{"emptyLinePlaceholder":125},[101,1129,1130],{"class":103,"line":182},[101,1131,1132],{},"    public record Config(int timeout, int retries) {}\n",[101,1134,1135],{"class":103,"line":187},[101,1136,190],{},[10,1138,1139],{},"读线程每次先取得一次快照：",[91,1141,1143],{"className":93,"code":1142,"language":95,"meta":96,"style":96},"ConfigCenter.Config snapshot = ConfigCenter.current();\nuse(snapshot.timeout(), snapshot.retries());\n",[98,1144,1145,1150],{"__ignoreMap":96},[101,1146,1147],{"class":103,"line":104},[101,1148,1149],{},"ConfigCenter.Config snapshot = ConfigCenter.current();\n",[101,1151,1152],{"class":103,"line":110},[101,1153,1154],{},"use(snapshot.timeout(), snapshot.retries());\n",[10,1156,1157],{},"这样读线程看到的要么是完整的旧配置，要么是完整的新配置，不会看到一个被逐字段修改的中间状态。",[10,1159,1160],{},"错误方式是先发布引用，再继续修改对象：",[91,1162,1164],{"className":93,"code":1163,"language":95,"meta":96,"style":96},"config = new Config(); \u002F\u002F 已经发布\nconfig.setTimeout(3000);\nconfig.setEndpoint(\"https:\u002F\u002Fexample.com\");\n",[98,1165,1166,1171,1176],{"__ignoreMap":96},[101,1167,1168],{"class":103,"line":104},[101,1169,1170],{},"config = new Config(); \u002F\u002F 已经发布\n",[101,1172,1173],{"class":103,"line":110},[101,1174,1175],{},"config.setTimeout(3000);\n",[101,1177,1178],{"class":103,"line":116},[101,1179,1180],{},"config.setEndpoint(\"https:\u002F\u002Fexample.com\");\n",[10,1182,1183,1185,1186,1189],{},[98,1184,234],{}," 修饰的是引用，并不会让对象内部后续修改自动具有原子性。多个写线程如果需要避免相互覆盖，仍要使用锁、",[98,1187,1188],{},"AtomicReference.compareAndSet"," 或版本号。",[28,1191,1192],{"id":1192},"安全发布不等于后续线程安全",[10,1194,1195],{},"安全发布只保证对象交给其他线程的那一刻，初始化状态完整可见。如果发布后对象仍然可变，后续并发读写仍需使用锁、volatile 字段、原子类、并发容器，或者改为不可变对象整体替换。",[10,1197,1198],{},"需要区分三件事：",[91,1200,1203],{"className":1201,"code":1202,"language":500,"meta":96},[498],"正确构造：对象内部初始化完整，构造期间 this 不逸出\n安全发布：通过 happens-before 把完整对象交给其他线程\n后续线程安全：发布后的每一次共享状态修改都有并发保护\n",[98,1204,1202],{"__ignoreMap":96},[28,1206,1207],{"id":1207},"常见误区",[210,1209,1211],{"id":1210},"jmm-就是堆栈方法区","“JMM 就是堆、栈、方法区”",[10,1213,1214],{},"错误。那是 JVM 运行时内存区域；JMM 是并发访问共享变量的规则。",[210,1216,1218],{"id":1217},"volatile-能保证线程安全","“volatile 能保证线程安全”",[10,1220,1221,1222,1225],{},"不准确。它保证可见性和特定有序性，不能让 ",[98,1223,1224],{},"count++"," 等复合操作原子化。",[210,1227,1229],{"id":1228},"final-对象天然不可变线程安全","“final 对象天然不可变、线程安全”",[10,1231,1232,1233,1235],{},"错误。",[98,1234,717],{}," 引用不能重新赋值，但引用指向的对象仍可能被修改。",[210,1237,1239],{"id":1238},"字段是-static所以写入就是安全发布","“字段是 static，所以写入就是安全发布”",[10,1241,1242],{},"错误。普通静态方法中的赋值仍然是共享变量的普通写；只有类初始化、volatile、锁等机制才能建立明确的发布保证。",[210,1244,1246],{"id":1245},"cpu-有缓存一致性协议所以不需要-jmm","“CPU 有缓存一致性协议，所以不需要 JMM”",[10,1248,1249],{},"错误。缓存一致性不能单独覆盖 Store Buffer、编译器与 CPU 重排序、JVM 优化和不同硬件内存模型差异。JMM 为 Java 程序提供跨平台的统一语义。",[28,1251,1252],{"id":1252},"面试回答模板",[22,1254,1255],{},[10,1256,1257],{},"JMM 是 Java 并发访问共享变量的规范，核心解决原子性、可见性和有序性问题。它通过 happens-before 规则定义一个线程的写入何时必须对另一个线程可见。volatile 写与后续读、同一把锁的释放与获取、线程 start 和 join 都能建立 happens-before。volatile 适合状态标志和不可变对象引用的安全发布，但不能保证复合操作原子性；synchronized 则同时提供临界区原子性、可见性和必要的有序性。final 字段具有特殊初始化语义，但前提是构造期间 this 不逸出。对象安全发布后，如果还会发生并发修改，仍需要额外的线程安全措施。",[28,1259,1260],{"id":1260},"复习检查清单",[484,1262,1263,1266,1273,1276,1279,1282,1288,1291,1294,1297],{},[243,1264,1265],{},"能否解释 JMM 与 JVM 内存区域的区别？",[243,1267,1268,1269,1272],{},"为什么 ",[98,1270,1271],{},"volatile int count; count++"," 仍不安全？",[243,1274,1275],{},"happens-before 提供的是哪两类保证？",[243,1277,1278],{},"volatile 写和读如何安全发布普通字段的写入？",[243,1280,1281],{},"DCL 单例为什么必须使用 volatile？",[243,1283,1284,1285,1287],{},"final 字段语义的前提为什么是 ",[98,1286,787],{}," 不逸出？",[243,1289,1290],{},"静态字段与 JVM 静态初始化有什么区别？",[243,1292,1293],{},"安全发布为什么不等于对象后续线程安全？",[243,1295,1296],{},"如何用不可变对象加 volatile 引用实现配置热更新？",[243,1298,1299],{},"多个写线程更新快照时为什么可能还需要 CAS 或锁？",[28,1301,1302],{"id":1302},"参考资料",[240,1304,1305,1314],{},[243,1306,1307],{},[1308,1309,1313],"a",{"href":1310,"rel":1311},"https:\u002F\u002Fdocs.oracle.com\u002Fjavase\u002Fspecs\u002Fjls\u002Fse25\u002Fhtml\u002Fjls-17.html",[1312],"nofollow","Java Language Specification：Threads and Locks",[243,1315,1316],{},[1308,1317,1320],{"href":1318,"rel":1319},"https:\u002F\u002Fdocs.oracle.com\u002Fen\u002Fjava\u002Fjavase\u002F25\u002Fdocs\u002Fapi\u002Fjava.base\u002Fjava\u002Futil\u002Fconcurrent\u002Fpackage-summary.html#MemoryVisibility",[1312],"Java SE API：java.util.concurrent 的内存一致性属性",[1322,1323,1324],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":96,"searchDepth":110,"depth":110,"links":1326},[1327,1328,1329,1334,1335,1338,1339,1343,1346,1347,1348,1355,1356,1357],{"id":30,"depth":110,"text":31},{"id":85,"depth":110,"text":86},{"id":208,"depth":110,"text":208,"children":1330},[1331,1332,1333],{"id":212,"depth":116,"text":212},{"id":263,"depth":116,"text":263},{"id":295,"depth":116,"text":295},{"id":304,"depth":110,"text":305},{"id":476,"depth":110,"text":477,"children":1336},[1337],{"id":532,"depth":116,"text":533},{"id":626,"depth":110,"text":627},{"id":711,"depth":110,"text":712,"children":1340},[1341,1342],{"id":780,"depth":116,"text":781},{"id":859,"depth":116,"text":860},{"id":887,"depth":110,"text":887,"children":1344},[1345],{"id":979,"depth":116,"text":979},{"id":1054,"depth":110,"text":1055},{"id":1192,"depth":110,"text":1192},{"id":1207,"depth":110,"text":1207,"children":1349},[1350,1351,1352,1353,1354],{"id":1210,"depth":116,"text":1211},{"id":1217,"depth":116,"text":1218},{"id":1228,"depth":116,"text":1229},{"id":1238,"depth":116,"text":1239},{"id":1245,"depth":116,"text":1246},{"id":1252,"depth":110,"text":1252},{"id":1260,"depth":110,"text":1260},{"id":1302,"depth":110,"text":1302},"wiki:java:java-memory-model","从原子性、可见性、有序性出发，系统理解 happens-before、volatile、final 字段语义和对象安全发布。","advanced",false,"md",{},31,"\u002Fjava\u002Fjava-memory-model","并发编程",{"title":5,"description":1359},"java\u002Fjava-memory-model","2026-07-15","XB6ea7s7ydc5hO9YSGkFZyTqRMEbD1zjRPTfDfa856k",[1372,1459,1570,1669,1765,1840,1910],{"id":1373,"title":1374,"body":1375,"commentId":1449,"description":1450,"difficulty":1451,"draft":1361,"extension":1362,"meta":1452,"navigation":125,"order":104,"path":1453,"section":1454,"seo":1455,"stem":1456,"updated":1457,"__hash__":1458},"java\u002Fjava\u002Ffundamentals.md","Java 基础知识地图",{"type":7,"value":1376,"toc":1443},[1377,1380,1383,1386,1409,1412,1415,1418],[28,1378,1379],{"id":1379},"这一部分解决什么问题",[10,1381,1382],{},"Java 基础不是 API 的罗列，而是理解类型、对象和运行时行为之间的关系。后续的并发、JVM 和框架知识都建立在这些概念之上。",[28,1384,1385],{"id":1385},"知识路线",[484,1387,1388,1391,1397,1400,1403,1406],{},[243,1389,1390],{},"基本类型、包装类型与自动装箱",[243,1392,1393,1396],{},[98,1394,1395],{},"String","、不可变对象与对象比较",[243,1398,1399],{},"集合框架与常见数据结构",[243,1401,1402],{},"泛型、类型擦除与边界",[243,1404,1405],{},"反射、注解与动态代理",[243,1407,1408],{},"异常体系和资源管理",[28,1410,1411],{"id":1411},"推荐学习方式",[10,1413,1414],{},"先用一句话回答“它是什么”，再通过小段代码验证边界，最后把它放回 JVM 和框架运行机制中理解。知识库会逐步把每个主题拆成独立条目。",[28,1416,1417],{"id":1417},"面试时容易出现的问题",[240,1419,1420,1427,1437,1440],{},[243,1421,1422,1423,1426],{},"只背诵 ",[98,1424,1425],{},"HashMap"," 的结论，不理解哈希冲突和扩容成本。",[243,1428,850,1429,1432,1433,1436],{},[98,1430,1431],{},"=="," 和 ",[98,1434,1435],{},"equals"," 简化成“地址比较”和“内容比较”。",[243,1438,1439],{},"知道泛型语法，但无法解释类型擦除带来的限制。",[243,1441,1442],{},"会使用反射，却不了解它为什么被 Spring 等框架广泛使用。",{"title":96,"searchDepth":110,"depth":110,"links":1444},[1445,1446,1447,1448],{"id":1379,"depth":110,"text":1379},{"id":1385,"depth":110,"text":1385},{"id":1411,"depth":110,"text":1411},{"id":1417,"depth":110,"text":1417},"wiki:java:fundamentals","Java 类型系统、集合、泛型、反射、异常与常用语言机制的学习入口。","basic",{},"\u002Fjava\u002Ffundamentals","Java 基础",{"title":1374,"description":1450},"java\u002Ffundamentals","2026-07-10","TZ18cq4bXSr9iscSOTSlgfMfbmTp2H5kOdVxAbnY_2s",{"id":1460,"title":1461,"body":1462,"commentId":1561,"description":1562,"difficulty":1563,"draft":1361,"extension":1362,"meta":1564,"navigation":125,"order":110,"path":1565,"section":1566,"seo":1567,"stem":1568,"updated":1457,"__hash__":1569},"java\u002Fjava\u002Fjvm.md","JVM 知识地图",{"type":7,"value":1463,"toc":1551},[1464,1468,1471,1473,1476,1490,1493,1507,1510,1524,1527,1541,1544],[28,1465,1467],{"id":1466},"为什么要理解-jvm","为什么要理解 JVM",[10,1469,1470],{},"JVM 把 Java 源代码和具体硬件隔开，但生产问题最终仍会落到内存、线程、字节码和操作系统资源上。理解 JVM 的目标不是记参数，而是能解释和诊断程序行为。",[28,1472,1385],{"id":1385},[210,1474,1475],{"id":1475},"类加载",[240,1477,1478,1481,1484,1487],{},[243,1479,1480],{},"加载、验证、准备、解析和初始化",[243,1482,1483],{},"双亲委派模型",[243,1485,1486],{},"类加载器隔离",[243,1488,1489],{},"静态字段和初始化顺序",[210,1491,1492],{"id":1492},"运行时数据区",[240,1494,1495,1498,1501,1504],{},[243,1496,1497],{},"堆与对象分配",[243,1499,1500],{},"虚拟机栈与栈帧",[243,1502,1503],{},"方法区与元空间",[243,1505,1506],{},"直接内存",[210,1508,1509],{"id":1509},"垃圾回收",[240,1511,1512,1515,1518,1521],{},[243,1513,1514],{},"可达性分析",[243,1516,1517],{},"分代收集",[243,1519,1520],{},"CMS、G1 与现代收集器",[243,1522,1523],{},"停顿时间、吞吐量和内存占用之间的权衡",[210,1525,1526],{"id":1526},"性能排查",[240,1528,1529,1532,1535,1538],{},[243,1530,1531],{},"GC 日志",[243,1533,1534],{},"线程快照",[243,1536,1537],{},"堆转储",[243,1539,1540],{},"CPU、内存和锁竞争定位",[28,1542,1543],{"id":1543},"一句话原则",[10,1545,1546,1547,1550],{},"先确定现象属于 CPU、内存、线程还是外部依赖，再选择工具；不要看到 ",[98,1548,1549],{},"OutOfMemoryError"," 就先调整堆大小。",{"title":96,"searchDepth":110,"depth":110,"links":1552},[1553,1554,1560],{"id":1466,"depth":110,"text":1467},{"id":1385,"depth":110,"text":1385,"children":1555},[1556,1557,1558,1559],{"id":1475,"depth":116,"text":1475},{"id":1492,"depth":116,"text":1492},{"id":1509,"depth":116,"text":1509},{"id":1526,"depth":116,"text":1526},{"id":1543,"depth":110,"text":1543},"wiki:java:jvm","从类加载、运行时内存到垃圾回收与性能排查，理解 Java 程序如何真正运行。","intermediate",{},"\u002Fjava\u002Fjvm","JVM",{"title":1461,"description":1562},"java\u002Fjvm","ZPK0OT5czgBvYvU-AowqKfXfaGqS5bqnDP2N5bWKN5k",{"id":1571,"title":1572,"body":1573,"commentId":1662,"description":1663,"difficulty":1563,"draft":1361,"extension":1362,"meta":1664,"navigation":125,"order":116,"path":1665,"section":1366,"seo":1666,"stem":1667,"updated":1457,"__hash__":1668},"java\u002Fjava\u002Fconcurrency.md","Java 并发知识地图",{"type":7,"value":1574,"toc":1653},[1575,1578,1580,1586,1588,1597,1599,1602,1604,1636,1639],[28,1576,1577],{"id":1577},"并发问题的三个核心维度",[210,1579,263],{"id":263},[10,1581,1582,1583,1585],{},"一个线程修改的数据，何时能够被另一个线程观察到。",[98,1584,234],{},"、锁和线程启动\u002F终止规则都与 happens-before 有关。",[210,1587,212],{"id":212},[10,1589,1590,1591,1593,1594,1596],{},"一个操作能否被其他线程观察到中间状态。",[98,1592,1224],{}," 即使使用 ",[98,1595,234],{}," 也不是原子操作。",[210,1598,295],{"id":295},[10,1600,1601],{},"编译器和处理器可以在不改变单线程结果的前提下重排序。并发程序必须通过同步规则建立必要顺序。",[28,1603,1385],{"id":1385},[484,1605,1606,1609,1614,1619,1622,1625,1628,1634],{},[243,1607,1608],{},"Java 内存模型与 happens-before",[243,1610,1611,1613],{},[98,1612,234],{}," 与内存屏障",[243,1615,1616,1618],{},[98,1617,247],{}," 与对象监视器",[243,1620,1621],{},"CAS、原子类和 ABA 问题",[243,1623,1624],{},"AQS、锁和同步器",[243,1626,1627],{},"线程池与任务调度",[243,1629,1630,1633],{},[98,1631,1632],{},"CompletableFuture"," 与异步编排",[243,1635,948],{},[28,1637,1638],{"id":1638},"生产实践原则",[240,1640,1641,1644,1647,1650],{},[243,1642,1643],{},"尽量减少共享可变状态。",[243,1645,1646],{},"明确线程池的职责、队列容量和拒绝策略。",[243,1648,1649],{},"不要把耗时不可控的任务提交到公共线程池。",[243,1651,1652],{},"监控活跃线程数、队列长度、拒绝次数和任务耗时。",{"title":96,"searchDepth":110,"depth":110,"links":1654},[1655,1660,1661],{"id":1577,"depth":110,"text":1577,"children":1656},[1657,1658,1659],{"id":263,"depth":116,"text":263},{"id":212,"depth":116,"text":212},{"id":295,"depth":116,"text":295},{"id":1385,"depth":110,"text":1385},{"id":1638,"depth":110,"text":1638},"wiki:java:concurrency","理解可见性、原子性、有序性，以及 Java 并发工具如何建立在这些规则之上。",{},"\u002Fjava\u002Fconcurrency",{"title":1572,"description":1663},"java\u002Fconcurrency","EkMZP12_4LdF-05WBbKP344weaqz3uif-3l5nazF3xk",{"id":1670,"title":1671,"body":1672,"commentId":1757,"description":1758,"difficulty":1563,"draft":1361,"extension":1362,"meta":1759,"navigation":125,"order":122,"path":1760,"section":1761,"seo":1762,"stem":1763,"updated":1457,"__hash__":1764},"java\u002Fjava\u002Fspring.md","Spring 知识地图",{"type":7,"value":1673,"toc":1750},[1674,1678,1681,1685,1702,1706,1720,1723,1740,1743],[28,1675,1677],{"id":1676},"理解-spring-的主线","理解 Spring 的主线",[10,1679,1680],{},"Spring 的核心不是注解数量，而是容器如何创建对象、建立依赖，并在合适的扩展点改变对象行为。",[28,1682,1684],{"id":1683},"ioc-容器","IOC 容器",[240,1686,1687,1690,1693,1696,1699],{},[243,1688,1689],{},"BeanDefinition 的来源",[243,1691,1692],{},"Bean 创建生命周期",[243,1694,1695],{},"依赖注入",[243,1697,1698],{},"BeanPostProcessor",[243,1700,1701],{},"循环依赖",[28,1703,1705],{"id":1704},"aop","AOP",[240,1707,1708,1711,1714,1717],{},[243,1709,1710],{},"JDK 动态代理和 CGLIB",[243,1712,1713],{},"切点与通知",[243,1715,1716],{},"代理对象调用边界",[243,1718,1719],{},"自调用为什么可能导致切面失效",[28,1721,1722],{"id":1722},"事务",[240,1724,1725,1728,1731,1734,1737],{},[243,1726,1727],{},"事务管理器",[243,1729,1730],{},"传播行为",[243,1732,1733],{},"隔离级别",[243,1735,1736],{},"回滚规则",[243,1738,1739],{},"声明式事务失效场景",[28,1741,1742],{"id":1742},"学习建议",[10,1744,1745,1746,1749],{},"选择一条最短链路，从 ",[98,1747,1748],{},"ApplicationContext"," 启动到一个带事务的 Service 被调用，跟踪其中的对象创建、代理生成和拦截过程。这样比孤立背诵源码类名更有效。",{"title":96,"searchDepth":110,"depth":110,"links":1751},[1752,1753,1754,1755,1756],{"id":1676,"depth":110,"text":1677},{"id":1683,"depth":110,"text":1684},{"id":1704,"depth":110,"text":1705},{"id":1722,"depth":110,"text":1722},{"id":1742,"depth":110,"text":1742},"wiki:java:spring","从 IOC、AOP 和事务出发，理解 Spring 如何组织和增强应用程序。",{},"\u002Fjava\u002Fspring","Spring",{"title":1671,"description":1758},"java\u002Fspring","jZmHr0WwrtcGUGlcEdj8z-shlR3YZc-UdEZSfPZYgNE",{"id":1766,"title":1767,"body":1768,"commentId":1832,"description":1833,"difficulty":1563,"draft":1361,"extension":1362,"meta":1834,"navigation":125,"order":129,"path":1835,"section":1836,"seo":1837,"stem":1838,"updated":1457,"__hash__":1839},"java\u002Fjava\u002Fdatabase.md","数据库与缓存知识地图",{"type":7,"value":1769,"toc":1826},[1770,1773,1776,1780,1800,1803,1820,1823],[28,1771,1772],{"id":1772},"数据库知识的核心问题",[10,1774,1775],{},"后端开发关注的不只是 SQL 能否执行，还要理解数据如何被定位、并发修改如何协调、失败后如何恢复，以及缓存加入后怎样维持可接受的一致性。",[28,1777,1779],{"id":1778},"mysql","MySQL",[240,1781,1782,1785,1788,1791,1794,1797],{},[243,1783,1784],{},"B+Tree 与索引组织",[243,1786,1787],{},"联合索引和最左匹配",[243,1789,1790],{},"执行计划",[243,1792,1793],{},"MVCC 与 Read View",[243,1795,1796],{},"行锁、间隙锁和死锁",[243,1798,1799],{},"redo log、undo log 与 binlog",[28,1801,1802],{"id":1802},"缓存",[240,1804,1805,1808,1811,1814,1817],{},[243,1806,1807],{},"Cache Aside",[243,1809,1810],{},"缓存穿透、击穿和雪崩",[243,1812,1813],{},"热点 Key",[243,1815,1816],{},"数据更新与失效",[243,1818,1819],{},"最终一致性",[28,1821,1822],{"id":1822},"排查顺序",[10,1824,1825],{},"面对慢查询，先确认实际执行 SQL 和参数，再看执行计划、扫描行数、锁等待和数据分布。不要只根据 SQL 外观判断是否使用索引。",{"title":96,"searchDepth":110,"depth":110,"links":1827},[1828,1829,1830,1831],{"id":1772,"depth":110,"text":1772},{"id":1778,"depth":110,"text":1779},{"id":1802,"depth":110,"text":1802},{"id":1822,"depth":110,"text":1822},"wiki:java:database","围绕索引、事务、锁、缓存与数据一致性，建立后端开发需要的数据库认知。",{},"\u002Fjava\u002Fdatabase","数据库",{"title":1767,"description":1833},"java\u002Fdatabase","3gza7dGQZPwMSHFISiZ7Jy-iB_2rQD2ozomZ8OuiyHw",{"id":1841,"title":1842,"body":1843,"commentId":1902,"description":1903,"difficulty":1451,"draft":1361,"extension":1362,"meta":1904,"navigation":125,"order":135,"path":1905,"section":1906,"seo":1907,"stem":1908,"updated":1457,"__hash__":1909},"java\u002Fjava\u002Finterview.md","Java 面试专题使用说明",{"type":7,"value":1844,"toc":1897},[1845,1848,1851,1854,1885,1888,1894],[28,1846,1847],{"id":1847},"这里不会做什么",[10,1849,1850],{},"不会把数百道问题堆在一个页面，也不会只给出适合背诵但无法解释的标准答案。",[28,1852,1853],{"id":1853},"每个问题的组织方式",[484,1855,1856,1862,1868,1874,1879],{},[243,1857,1858,1861],{},[14,1859,1860],{},"一句话回答","：先准确回答问题。",[243,1863,1864,1867],{},[14,1865,1866],{},"核心原理","：说明这个结论为什么成立。",[243,1869,1870,1873],{},[14,1871,1872],{},"代码验证","：使用尽可能小的例子验证边界。",[243,1875,1876,1878],{},[14,1877,1207],{},"：指出容易混淆的地方。",[243,1880,1881,1884],{},[14,1882,1883],{},"继续追问","：把当前问题连接到更深层知识。",[28,1886,1887],{"id":1887},"示例追问链",[91,1889,1892],{"className":1890,"code":1891,"language":500,"meta":96},[498],"HashMap 为什么线程不安全？\n  → put 操作包含哪些步骤？\n  → 扩容时发生什么？\n  → ConcurrentHashMap 如何降低竞争？\n  → JDK 不同版本的实现有什么变化？\n",[98,1893,1891],{"__ignoreMap":96},[10,1895,1896],{},"面试题的价值不是预测题目，而是帮助自己检查知识之间是否已经形成连接。",{"title":96,"searchDepth":110,"depth":110,"links":1898},[1899,1900,1901],{"id":1847,"depth":110,"text":1847},{"id":1853,"depth":110,"text":1853},{"id":1887,"depth":110,"text":1887},"wiki:java:interview","用简明回答、原理解释、代码验证和追问路径组织 Java 面试知识。",{},"\u002Fjava\u002Finterview","面试专题",{"title":1842,"description":1903},"java\u002Finterview","AWxAYmdi1IahbXu7QwVZPfsiCXbVU4YTMMoshQkzEl8",{"id":4,"title":5,"body":1911,"commentId":1358,"description":1359,"difficulty":1360,"draft":1361,"extension":1362,"meta":2904,"navigation":125,"order":1364,"path":1365,"section":1366,"seo":2905,"stem":1368,"updated":1369,"__hash__":1370},{"type":7,"value":1912,"toc":2871},[1913,1917,1919,1923,1925,1927,1957,1959,1961,1963,2027,2035,2037,2039,2041,2049,2055,2057,2071,2073,2075,2077,2093,2095,2099,2101,2103,2107,2109,2169,2171,2219,2227,2229,2233,2239,2241,2246,2250,2262,2266,2268,2336,2342,2344,2348,2362,2364,2410,2412,2420,2460,2464,2466,2470,2510,2512,2526,2528,2540,2546,2548,2550,2552,2614,2616,2618,2650,2654,2670,2674,2676,2680,2744,2746,2758,2760,2762,2778,2784,2786,2788,2790,2795,2797,2799,2801,2803,2807,2809,2813,2815,2817,2819,2821,2823,2827,2829,2855,2857,2869],[10,1914,12,1915,17],{},[14,1916,16],{},[10,1918,20],{},[22,1920,1921],{},[10,1922,26],{},[28,1924,31],{"id":30},[10,1926,34],{},[36,1928,1929,1939],{},[39,1930,1931],{},[42,1932,1933,1935,1937],{},[45,1934,47],{},[45,1936,50],{},[45,1938,53],{},[55,1940,1941,1949],{},[42,1942,1943,1945,1947],{},[60,1944,62],{},[60,1946,65],{},[60,1948,68],{},[42,1950,1951,1953,1955],{},[60,1952,73],{},[60,1954,76],{},[60,1956,79],{},[10,1958,82],{},[28,1960,86],{"id":85},[10,1962,89],{},[91,1964,1965],{"className":93,"code":94,"language":95,"meta":96,"style":96},[98,1966,1967,1971,1975,1979,1983,1987,1991,1995,1999,2003,2007,2011,2015,2019,2023],{"__ignoreMap":96},[101,1968,1969],{"class":103,"line":104},[101,1970,107],{},[101,1972,1973],{"class":103,"line":110},[101,1974,113],{},[101,1976,1977],{"class":103,"line":116},[101,1978,119],{},[101,1980,1981],{"class":103,"line":122},[101,1982,126],{"emptyLinePlaceholder":125},[101,1984,1985],{"class":103,"line":129},[101,1986,132],{},[101,1988,1989],{"class":103,"line":135},[101,1990,138],{},[101,1992,1993],{"class":103,"line":141},[101,1994,144],{},[101,1996,1997],{"class":103,"line":147},[101,1998,150],{},[101,2000,2001],{"class":103,"line":153},[101,2002,126],{"emptyLinePlaceholder":125},[101,2004,2005],{"class":103,"line":158},[101,2006,161],{},[101,2008,2009],{"class":103,"line":164},[101,2010,167],{},[101,2012,2013],{"class":103,"line":170},[101,2014,173],{},[101,2016,2017],{"class":103,"line":176},[101,2018,179],{},[101,2020,2021],{"class":103,"line":182},[101,2022,150],{},[101,2024,2025],{"class":103,"line":187},[101,2026,190],{},[10,2028,193,2029,197,2031,201,2033,205],{},[98,2030,196],{},[98,2032,200],{},[98,2034,204],{},[28,2036,208],{"id":208},[210,2038,212],{"id":212},[10,2040,215],{},[91,2042,2043],{"className":93,"code":218,"language":95,"meta":96,"style":96},[98,2044,2045],{"__ignoreMap":96},[101,2046,2047],{"class":103,"line":104},[101,2048,218],{},[10,2050,227,2051,231,2053,235],{},[98,2052,230],{},[98,2054,234],{},[10,2056,238],{},[240,2058,2059,2065,2069],{},[243,2060,2061,248,2063],{},[98,2062,247],{},[98,2064,251],{},[243,2066,254,2067],{},[98,2068,257],{},[243,2070,260],{},[210,2072,263],{"id":263},[10,2074,266],{},[10,2076,269],{},[240,2078,2079,2083,2085,2091],{},[243,2080,2081,276],{},[98,2082,234],{},[243,2084,279],{},[243,2086,2087,285,2089,289],{},[98,2088,284],{},[98,2090,288],{},[243,2092,292],{},[210,2094,295],{"id":295},[10,2096,298,2097,301],{},[98,2098,234],{},[28,2100,305],{"id":304},[10,2102,308],{},[10,2104,311,2105,315],{},[14,2106,314],{},[10,2108,318],{},[36,2110,2111,2119],{},[39,2112,2113],{},[42,2114,2115,2117],{},[45,2116,327],{},[45,2118,330],{},[55,2120,2121,2127,2133,2139,2147,2155,2163],{},[42,2122,2123,2125],{},[60,2124,337],{},[60,2126,340],{},[42,2128,2129,2131],{},[60,2130,345],{},[60,2132,348],{},[42,2134,2135,2137],{},[60,2136,353],{},[60,2138,356],{},[42,2140,2141,2143],{},[60,2142,361],{},[60,2144,364,2145,368],{},[98,2146,367],{},[42,2148,2149,2151],{},[60,2150,373],{},[60,2152,376,2153,380],{},[98,2154,379],{},[42,2156,2157,2159],{},[60,2158,385],{},[60,2160,364,2161,391],{},[98,2162,390],{},[42,2164,2165,2167],{},[60,2166,396],{},[60,2168,399],{},[10,2170,402],{},[91,2172,2173],{"className":93,"code":405,"language":95,"meta":96,"style":96},[98,2174,2175,2179,2183,2187,2191,2195,2199,2203,2207,2211,2215],{"__ignoreMap":96},[101,2176,2177],{"class":103,"line":104},[101,2178,412],{},[101,2180,2181],{"class":103,"line":110},[101,2182,417],{},[101,2184,2185],{"class":103,"line":116},[101,2186,126],{"emptyLinePlaceholder":125},[101,2188,2189],{"class":103,"line":122},[101,2190,426],{},[101,2192,2193],{"class":103,"line":129},[101,2194,431],{},[101,2196,2197],{"class":103,"line":135},[101,2198,436],{},[101,2200,2201],{"class":103,"line":141},[101,2202,126],{"emptyLinePlaceholder":125},[101,2204,2205],{"class":103,"line":147},[101,2206,445],{},[101,2208,2209],{"class":103,"line":153},[101,2210,450],{},[101,2212,2213],{"class":103,"line":158},[101,2214,455],{},[101,2216,2217],{"class":103,"line":164},[101,2218,190],{},[10,2220,2221,465,2223,469,2225,473],{},[98,2222,464],{},[98,2224,468],{},[98,2226,472],{},[28,2228,477],{"id":476},[10,2230,2231,482],{},[98,2232,234],{},[484,2234,2235,2237],{},[243,2236,488],{},[243,2238,491],{},[10,2240,494],{},[91,2242,2244],{"className":2243,"code":499,"language":500,"meta":96},[498],[98,2245,499],{"__ignoreMap":96},[10,2247,505,2248,508],{},[98,2249,234],{},[91,2251,2252],{"className":93,"code":511,"language":95,"meta":96,"style":96},[98,2253,2254,2258],{"__ignoreMap":96},[101,2255,2256],{"class":103,"line":104},[101,2257,518],{},[101,2259,2260],{"class":103,"line":110},[101,2261,523],{},[10,2263,526,2264,529],{},[98,2265,234],{},[210,2267,533],{"id":532},[91,2269,2270],{"className":93,"code":536,"language":95,"meta":96,"style":96},[98,2271,2272,2276,2280,2284,2288,2292,2296,2300,2304,2308,2312,2316,2320,2324,2328,2332],{"__ignoreMap":96},[101,2273,2274],{"class":103,"line":104},[101,2275,543],{},[101,2277,2278],{"class":103,"line":110},[101,2279,548],{},[101,2281,2282],{"class":103,"line":116},[101,2283,126],{"emptyLinePlaceholder":125},[101,2285,2286],{"class":103,"line":122},[101,2287,557],{},[101,2289,2290],{"class":103,"line":129},[101,2291,126],{"emptyLinePlaceholder":125},[101,2293,2294],{"class":103,"line":135},[101,2295,566],{},[101,2297,2298],{"class":103,"line":141},[101,2299,571],{},[101,2301,2302],{"class":103,"line":147},[101,2303,576],{},[101,2305,2306],{"class":103,"line":153},[101,2307,581],{},[101,2309,2310],{"class":103,"line":158},[101,2311,586],{},[101,2313,2314],{"class":103,"line":164},[101,2315,591],{},[101,2317,2318],{"class":103,"line":170},[101,2319,596],{},[101,2321,2322],{"class":103,"line":176},[101,2323,179],{},[101,2325,2326],{"class":103,"line":182},[101,2327,605],{},[101,2329,2330],{"class":103,"line":187},[101,2331,150],{},[101,2333,2334],{"class":103,"line":612},[101,2335,190],{},[10,2337,617,2338,620,2340,623],{},[98,2339,234],{},[98,2341,234],{},[28,2343,627],{"id":626},[10,2345,2346,632],{},[98,2347,247],{},[240,2349,2350,2354,2358],{},[243,2351,2352,639],{},[14,2353,212],{},[243,2355,2356,644],{},[14,2357,263],{},[243,2359,2360,650],{},[14,2361,649],{},[10,2363,653],{},[36,2365,2366,2376],{},[39,2367,2368],{},[42,2369,2370,2372,2374],{},[45,2371,662],{},[45,2373,234],{},[45,2375,247],{},[55,2377,2378,2386,2394,2402],{},[42,2379,2380,2382,2384],{},[60,2381,263],{},[60,2383,675],{},[60,2385,675],{},[42,2387,2388,2390,2392],{},[60,2389,682],{},[60,2391,675],{},[60,2393,675],{},[42,2395,2396,2398,2400],{},[60,2397,691],{},[60,2399,694],{},[60,2401,697],{},[42,2403,2404,2406,2408],{},[60,2405,702],{},[60,2407,705],{},[60,2409,708],{},[28,2411,712],{"id":711},[10,2413,2414,718,2416,721,2418,724],{},[98,2415,717],{},[98,2417,717],{},[98,2419,717],{},[91,2421,2422],{"className":93,"code":727,"language":95,"meta":96,"style":96},[98,2423,2424,2428,2432,2436,2440,2444,2448,2452,2456],{"__ignoreMap":96},[101,2425,2426],{"class":103,"line":104},[101,2427,734],{},[101,2429,2430],{"class":103,"line":110},[101,2431,739],{},[101,2433,2434],{"class":103,"line":116},[101,2435,744],{},[101,2437,2438],{"class":103,"line":122},[101,2439,126],{"emptyLinePlaceholder":125},[101,2441,2442],{"class":103,"line":129},[101,2443,753],{},[101,2445,2446],{"class":103,"line":135},[101,2447,758],{},[101,2449,2450],{"class":103,"line":141},[101,2451,763],{},[101,2453,2454],{"class":103,"line":147},[101,2455,150],{},[101,2457,2458],{"class":103,"line":153},[101,2459,190],{},[10,2461,774,2462,777],{},[98,2463,717],{},[210,2465,781],{"id":780},[10,2467,784,2468,788],{},[98,2469,787],{},[91,2471,2472],{"className":93,"code":791,"language":95,"meta":96,"style":96},[98,2473,2474,2478,2482,2486,2490,2494,2498,2502,2506],{"__ignoreMap":96},[101,2475,2476],{"class":103,"line":104},[101,2477,798],{},[101,2479,2480],{"class":103,"line":110},[101,2481,803],{},[101,2483,2484],{"class":103,"line":116},[101,2485,808],{},[101,2487,2488],{"class":103,"line":122},[101,2489,126],{"emptyLinePlaceholder":125},[101,2491,2492],{"class":103,"line":129},[101,2493,817],{},[101,2495,2496],{"class":103,"line":135},[101,2497,822],{},[101,2499,2500],{"class":103,"line":141},[101,2501,138],{},[101,2503,2504],{"class":103,"line":147},[101,2505,150],{},[101,2507,2508],{"class":103,"line":153},[101,2509,190],{},[10,2511,837],{},[240,2513,2514,2518,2520,2524],{},[243,2515,842,2516],{},[98,2517,787],{},[243,2519,847],{},[243,2521,850,2522,853],{},[98,2523,787],{},[243,2525,856],{},[210,2527,860],{"id":859},[91,2529,2530],{"className":93,"code":863,"language":95,"meta":96,"style":96},[98,2531,2532,2536],{"__ignoreMap":96},[101,2533,2534],{"class":103,"line":104},[101,2535,870],{},[101,2537,2538],{"class":103,"line":110},[101,2539,875],{},[10,2541,2542,880,2544,884],{},[98,2543,717],{},[98,2545,883],{},[28,2547,887],{"id":887},[10,2549,890],{},[10,2551,893],{},[36,2553,2554,2564],{},[39,2555,2556],{},[42,2557,2558,2560,2562],{},[45,2559,902],{},[45,2561,905],{},[45,2563,908],{},[55,2565,2566,2574,2582,2590,2598,2606],{},[42,2567,2568,2570,2572],{},[60,2569,915],{},[60,2571,918],{},[60,2573,921],{},[42,2575,2576,2578,2580],{},[60,2577,926],{},[60,2579,929],{},[60,2581,932],{},[42,2583,2584,2586,2588],{},[60,2585,937],{},[60,2587,940],{},[60,2589,943],{},[42,2591,2592,2594,2596],{},[60,2593,948],{},[60,2595,951],{},[60,2597,954],{},[42,2599,2600,2602,2604],{},[60,2601,959],{},[60,2603,962],{},[60,2605,965],{},[42,2607,2608,2610,2612],{},[60,2609,970],{},[60,2611,973],{},[60,2613,976],{},[210,2615,979],{"id":979},[10,2617,982],{},[91,2619,2620],{"className":93,"code":985,"language":95,"meta":96,"style":96},[98,2621,2622,2626,2630,2634,2638,2642,2646],{"__ignoreMap":96},[101,2623,2624],{"class":103,"line":104},[101,2625,992],{},[101,2627,2628],{"class":103,"line":110},[101,2629,997],{},[101,2631,2632],{"class":103,"line":116},[101,2633,126],{"emptyLinePlaceholder":125},[101,2635,2636],{"class":103,"line":122},[101,2637,1006],{},[101,2639,2640],{"class":103,"line":129},[101,2641,1011],{},[101,2643,2644],{"class":103,"line":135},[101,2645,150],{},[101,2647,2648],{"class":103,"line":141},[101,2649,190],{},[10,2651,1022,2652,1026],{},[98,2653,1025],{},[91,2655,2656],{"className":93,"code":1029,"language":95,"meta":96,"style":96},[98,2657,2658,2662,2666],{"__ignoreMap":96},[101,2659,2660],{"class":103,"line":104},[101,2661,992],{},[101,2663,2664],{"class":103,"line":110},[101,2665,1040],{},[101,2667,2668],{"class":103,"line":116},[101,2669,190],{},[10,2671,1047,2672,1051],{},[98,2673,1050],{},[28,2675,1055],{"id":1054},[10,2677,1058,2678,1062],{},[14,2679,1061],{},[91,2681,2682],{"className":93,"code":1065,"language":95,"meta":96,"style":96},[98,2683,2684,2688,2692,2696,2700,2704,2708,2712,2716,2720,2724,2728,2732,2736,2740],{"__ignoreMap":96},[101,2685,2686],{"class":103,"line":104},[101,2687,1072],{},[101,2689,2690],{"class":103,"line":110},[101,2691,1077],{},[101,2693,2694],{"class":103,"line":116},[101,2695,1082],{},[101,2697,2698],{"class":103,"line":122},[101,2699,126],{"emptyLinePlaceholder":125},[101,2701,2702],{"class":103,"line":129},[101,2703,1091],{},[101,2705,2706],{"class":103,"line":135},[101,2707,1096],{},[101,2709,2710],{"class":103,"line":141},[101,2711,150],{},[101,2713,2714],{"class":103,"line":147},[101,2715,126],{"emptyLinePlaceholder":125},[101,2717,2718],{"class":103,"line":153},[101,2719,1109],{},[101,2721,2722],{"class":103,"line":158},[101,2723,1114],{},[101,2725,2726],{"class":103,"line":164},[101,2727,1119],{},[101,2729,2730],{"class":103,"line":170},[101,2731,150],{},[101,2733,2734],{"class":103,"line":176},[101,2735,126],{"emptyLinePlaceholder":125},[101,2737,2738],{"class":103,"line":182},[101,2739,1132],{},[101,2741,2742],{"class":103,"line":187},[101,2743,190],{},[10,2745,1139],{},[91,2747,2748],{"className":93,"code":1142,"language":95,"meta":96,"style":96},[98,2749,2750,2754],{"__ignoreMap":96},[101,2751,2752],{"class":103,"line":104},[101,2753,1149],{},[101,2755,2756],{"class":103,"line":110},[101,2757,1154],{},[10,2759,1157],{},[10,2761,1160],{},[91,2763,2764],{"className":93,"code":1163,"language":95,"meta":96,"style":96},[98,2765,2766,2770,2774],{"__ignoreMap":96},[101,2767,2768],{"class":103,"line":104},[101,2769,1170],{},[101,2771,2772],{"class":103,"line":110},[101,2773,1175],{},[101,2775,2776],{"class":103,"line":116},[101,2777,1180],{},[10,2779,2780,1185,2782,1189],{},[98,2781,234],{},[98,2783,1188],{},[28,2785,1192],{"id":1192},[10,2787,1195],{},[10,2789,1198],{},[91,2791,2793],{"className":2792,"code":1202,"language":500,"meta":96},[498],[98,2794,1202],{"__ignoreMap":96},[28,2796,1207],{"id":1207},[210,2798,1211],{"id":1210},[10,2800,1214],{},[210,2802,1218],{"id":1217},[10,2804,1221,2805,1225],{},[98,2806,1224],{},[210,2808,1229],{"id":1228},[10,2810,1232,2811,1235],{},[98,2812,717],{},[210,2814,1239],{"id":1238},[10,2816,1242],{},[210,2818,1246],{"id":1245},[10,2820,1249],{},[28,2822,1252],{"id":1252},[22,2824,2825],{},[10,2826,1257],{},[28,2828,1260],{"id":1260},[484,2830,2831,2833,2837,2839,2841,2843,2847,2849,2851,2853],{},[243,2832,1265],{},[243,2834,1268,2835,1272],{},[98,2836,1271],{},[243,2838,1275],{},[243,2840,1278],{},[243,2842,1281],{},[243,2844,1284,2845,1287],{},[98,2846,787],{},[243,2848,1290],{},[243,2850,1293],{},[243,2852,1296],{},[243,2854,1299],{},[28,2856,1302],{"id":1302},[240,2858,2859,2864],{},[243,2860,2861],{},[1308,2862,1313],{"href":1310,"rel":2863},[1312],[243,2865,2866],{},[1308,2867,1320],{"href":1318,"rel":2868},[1312],[1322,2870,1324],{},{"title":96,"searchDepth":110,"depth":110,"links":2872},[2873,2874,2875,2880,2881,2884,2885,2889,2892,2893,2894,2901,2902,2903],{"id":30,"depth":110,"text":31},{"id":85,"depth":110,"text":86},{"id":208,"depth":110,"text":208,"children":2876},[2877,2878,2879],{"id":212,"depth":116,"text":212},{"id":263,"depth":116,"text":263},{"id":295,"depth":116,"text":295},{"id":304,"depth":110,"text":305},{"id":476,"depth":110,"text":477,"children":2882},[2883],{"id":532,"depth":116,"text":533},{"id":626,"depth":110,"text":627},{"id":711,"depth":110,"text":712,"children":2886},[2887,2888],{"id":780,"depth":116,"text":781},{"id":859,"depth":116,"text":860},{"id":887,"depth":110,"text":887,"children":2890},[2891],{"id":979,"depth":116,"text":979},{"id":1054,"depth":110,"text":1055},{"id":1192,"depth":110,"text":1192},{"id":1207,"depth":110,"text":1207,"children":2895},[2896,2897,2898,2899,2900],{"id":1210,"depth":116,"text":1211},{"id":1217,"depth":116,"text":1218},{"id":1228,"depth":116,"text":1229},{"id":1238,"depth":116,"text":1239},{"id":1245,"depth":116,"text":1246},{"id":1252,"depth":110,"text":1252},{"id":1260,"depth":110,"text":1260},{"id":1302,"depth":110,"text":1302},{},{"title":5,"description":1359},1784111419919]