一 .解释
1.内存可见性(Memory Visibility)是指当某个线程正在使用对象状态 而另一个线程在同时修改该状态,需要确保当一个线程修改了对象 状态后,其他线程能够看到发生的状态变化。
2. 可见性错误是指当读操作与写操作在不同的线程中执行时,我们无 法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚 至是根本不可能的事情。
3.我们可以通过同步来保证对象被安全地发布。除此之外我们也可以 使用一种更加轻量级的 volatile 变量。
4.Java 提供了一种稍弱的同步机制,即 volatile 变 量,用来确保将变量的更新操作通知到其他线程。 可以将 volatile 看做一个轻量级的锁,但是又与 锁有些不同:
4.1对于多线程,不是一种互斥关系 ;
4.2 不能保证变量状态的“原子性操作”;如(i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”)
二. 测试Demo如下:
/*
* 一、volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。
* 相较于 synchronized 是一种较为轻量级的同步策略。
*
* 注意:
* 1. volatile 不具备“互斥性”
* 2. volatile 不能保证变量的“原子性”
*/
public class TestVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while(true){
if(td.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
三.如何解决(针对volatile)
共享数据可以用原子变量,(原子变量:在 java.util.concurrent.atomic 包下提供了一些原子变量)
特点:1.原子变量底层都被 volatile 保证内存可见性
2. 利用CAS(Compare-And-Swap) 算法又保证数据变量的原子性
其中CAS 算法是硬件对于并发操作的支持针对多处理器 操作而设计的处理器中的一种特殊指令,用于管理对共享数据 的 并 发访问。
CAS 包含了三个操作数:
①内存值 V(刚开始线程读取的值)
②预估值 A (将要修改时再次读取的值)
③更新值 B (将要改成的值)
当且仅当 V == A 时, V = B; 否则,不会执行任何操作。
// private volatile int serialNumber = 0; serialNumber ++;
private AtomicInteger serialNumber = new AtomicInteger(0); serialNumber.getAndIncrement();//自增