一、简单例子解释一下工作内存和主内存的区别
@Slf4j
public class DemoThread {
//volatile
public static Boolean initFlag = false;
public static void changeFlag() {
log.info("-----------ready to changeFlg");
initFlag = true;
log.info("-----------changeFlg success");
}
public static void main(String[] args) {
new Thread(() -> {
while (!initFlag) {
}
log.info("-----------Thread1 catch the change");
}).start();
try {
Thread.sleep(500);
} catch (Exception e) {
}
new Thread(() -> {
changeFlag();
}).start();
}
}
执行结果是thread1无法监听到标志位变更的事件,原因就在于每个线程在cpu中都有自己的工作内存
想解决本问题只需要修改其中的一行指令:
public volatile static Boolean initFlag=false;
二、MESI协议
MESI
(Modified Exclusive Shared Or Invalid
)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议。
MESI协议中的状态#
CPU
中每个缓存行(caceh line
)使用4种状态进行标记(使用额外的两位(bit
)表示):
M: 被修改(Modified)
该缓存行只被缓存在该CPU
的缓存中,并且是被修改过的(dirty
),即与主存中的数据不一致,该缓存行中的内存需要在未来的某个时间点(允许其它CPU
读取请主存中相应内存之前)写回(write back
)主存。
当被写回主存之后,该缓存行的状态会变成独享(exclusive
)状态。
E: 独享的(Exclusive)
该缓存行只被缓存在该CPU
的缓存中,它是未被修改过的(clean
),与主存中数据一致。该状态可以在任何时刻当有其它CPU
读取该内存时变成共享状态(shared
)。
同样地,当CPU
修改该缓存行中内容时,该状态可以变成Modified
状态。
S: 共享的(Shared)
该状态意味着该缓存行可能被多个CPU
缓存,并且各个缓存中的数据与主存数据一致(clean
),当有一个CPU
修改该缓存行中,其它CPU
中该缓存行可以被作废(变成无效状态(Invalid
))。
I: 无效的(Invalid)
该缓存是无效的(可能有其它CPU
修改了该缓存行)。
最后汇总一下JVM常见配置
堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。