实例:
两个线程同时执行的情况下,执行i++ 操作,i初始化为1,得到的结果并非为3,而是2.过程为:
线程1和2 同时从主存中获取i 的值并写入缓存,在分别执行+1 操作,之后再分别写入主存,这时出现了最终主存的值为2的情况。这个是因为线程内操作对其他线程不可见,解决缓存一致性的方案有:
-
通过在总线加LOCK#锁的方式;
-
通过缓存一致性协议。
但是方案1的缺点是总线加锁会出现阻塞的情况,效率低。
方案2的核心思想是:缓存一致性协议(MESI协议)它确保每个缓存中使用的共享变量的副本是一致的。当某个CPU在写数据时,如果发现操作的变量是共享变量,则会通知其他CPU告知该变量的缓存行是无效的,因此其他CPU在读取该变量时,发现其无效会重新从主存中加载数据。
多线程并发的特点来源于:可见性,原子性和有序性
特点:
1、volatile 无法保证原子性操作(可理解为指令级别,java 对基本的数据类型的赋值操作进行了原子性操作的保证。但long和double 不是),
2、volatile 可保证可见性:当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,当其他线程读取共享变量时,它会直接从主内存中读取。当然,synchronize和锁都可以保证可见性。
3、在Java内存模型中,为了效率