1

volatile关键字,使一个变量在线程中可见

简单理解:一个类在运行时,其中的变量是放在java虚拟机内存模型的主存中,如果多线线程共同访问,会把这个变量copy一份到自己的工作内存中.如果一个线程修改了这个变量,并更新到主内存中,但是另一个线程不一定会及时的去主存中读取数据,可能每次读取的都是自己工作内存中的数据(什么时候去主内存中读取数据,由CPU自己决定)
那么volatile关键字,可以保证一个线程修改了成员变量,会通知其他线程访问的这个变量的时候,重新去主存中读取

下面代码显示,不使用volatile出现的问题

public class Seatiger {
    boolean running = true;
    
    void test(){
        System.out.println("test start");
        while(running){
        }
        System.out.println("test end");
    }
    
    public static void main(String[] args) {
        Seatiger seatiger = new Seatiger();
        new Thread(()->seatiger.test()).start();
        //睡一秒钟
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        seatiger.running = false;
    }
}

启动一条线程,运行test,一秒钟后,主线程把成员变量running变成false,但是test没有结束.
1576503996(1).jpg
由图可见,线程1可能不去从主存中读取数据,所以两个线程之间的变量就不可见

什么时候去主存中读取数据,由CPU自己决定,如果在while(running)让线程睡一会儿,那么,CPU可能就有多余的时间去主存中读取数据

如果使用

volatile boolean running = true;

那面就能保存线程之间时可见的,一个线程修改了成员变量,另一个线程一定可以及时的获取到

需要注意的是,虽然volatile可以保证线程之间时可见的,但是不能保证多线程操作同一个变量所带来的数据不一致性问题

image.png
虽然对同一个i加了两次,但是实际只加了一次,volatile 只能保证,其他线程读取的数据,是从主存中获取的

###### 也就是说volatile不能替代synchronized

如果操作要操持原子性,还得使用synchronized锁机制

如果只是对一个变量的简单操作,如加减,需要在并发下保持数据的一致性,可以使用java提供的具有原子性相关的类
如:AtomicInteger,AtomicLong,等其他Actomi开头的一些类


seatiger
0 声望0 粉丝