JMM对多线程的一些约束

it2025-01-27  15

多线程存在的问题

1.所见非所得 2.无法肉眼去检测程序的准确性。 3.不同的运行平台有不同的表现 4.错误难以重现。

典型代码

public class Demo{ int i = 0; boolean isRunning = true; public static void main(String[] args){ Demo demo = new Demo(); new Thread(){ public void run(){ while(isRunning){ demo.i++; } System.out.println(demo.i); } } Thread.sleep(30000); isRunning = false; System.out.println("shutdown"); } }

代码在jdk32位和64位的server和client运行结果不同。

原因
jdk32位server和jdk64位会进行指令优化,将isRunning缓存为true变为 if(isRunning){ while(true){ } }

可见性问题原因

1.cpu的高速缓存机制 2.java虚拟机对代码的优化。 java编程语言的语义允许Java编译器和微处理器进行执行优化。,这些优化导致了与代码不在同步,从而导致看似矛盾的行为。

解决

在java内存模型中规定:

使用volatile,修饰的变量,对其写入要和所有其他线程后续的读操作同步。因此, 使用volatile会禁止缓存,并且不做指令重排

JMM对于同步的规则定义

声明

JMM只对线程间操作生效,而对线程内无效

内容:

1.对volatile 变量V的写入,与所有其他线程后续对V的读同步 2.对于监视器m的解锁与所有后续操作对于m的加锁同步。 3.每个属性写入的默认值,与每个线程对其进行的操作同步 4.启动线程的操作和线程第一个操作同步 5.线程T2的最后操作和线程T1发现线程T2已经结束同步。 6.如果T1中断了T2那么其他线程会同步发现T2停止。通常抛出InterrruptedException。

final在jmm中的处理

1.final在该对象的狗仔函数中色湖之对象的字段,当线程看到该对象时,将始终看到该对象的final字段的正确构造。 2.如果在投在函数中设置字段后发生读取,则会看到该final字段分配的值,否则他将会看到默认值。

字节分裂处理

不要对byte[]进行重新赋值。更不要在多线程程序中这样做。存在赋值被覆盖

最新回复(0)