Java中 static 和 volatile 关键字的区别?

Java语言规范(Java Language Specification)的官方解释:

  1. If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created.
  2. A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable。
    还是迷糊,求解答。主要困惑是:
    既然static保证了唯一性,那么他对多个线程来说都是可见的啊,volatile保证了线程之间的可见性,那么修改的时候只要是原子操作,那么就会保证它的唯一性了吧。这两个在我理解上我觉得差不多。

需要了解的知识

static指的是类的静态成员,实例间共享
volatile跟Java的内存模型有关,线程执行时会将变量从主内存加载到线程工作内存,建立一个副本,在某个时刻写回。valatile指的每次都读取主内存的值,有更新则立即写回主内存。
理解了这两点,逐句再来解释你的困惑:

“既然static保证了唯一性”:static保证唯一性,指的是static修饰的静态成员变量是唯一的,多个实例共享这唯一一个成员。
“那么他对多个线程来说都是可见的啊”:这里,static其实跟线程没太大关系,应该说对多个对象实例是可见的。你说对多个线程可见,虽然没什么毛病,因为静态变量全局可见嘛,但是把这个理解转到线程的上线文中是困惑的起因。
“volatile保证了线程之间的可见性”:因为线程看到volatile变量会去读取主内存最新的值,而不是自个一直在那跟内部的变量副本玩,所以保证了valatile变量在各个线程间的可见性。
“那么修改的时候只要是原子操作,那么就会保证它的唯一性了吧”:此时你说的“唯一性”,指的是各个线程都能读取到唯一的最新的主内存变量,消除了线程工作内存加载变量副本可能带来的线程之间的“不唯一性”。这里“唯一性”的含义跟第一句说的“唯一性”是不一样的。
“这两个在我理解上我觉得差不多。”:其实解决问题的“场景”是完全不一样的。

造成理解困惑最大的原因在于,这两个场景略有类似,以致混淆了:

场景1:各个类的实例共享唯一一个类静态变量
场景2:各个线程共同读取唯一的最新的主内存变量的值

代码示例:
假如没有 static 关键字,那么使用同一个对象,才是可见的,如果不是同一个对象那么值不一致,除非加上 static 关键字,那么 Test1 种的变量才会同步:

public class Test1 {
    public volatile int  s1 = 0;
}
package com.xcewell.oms.api;


public class Test2 {
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        System.out.println(test1.s1);
                        test1.s1++;
                        Thread.sleep(3000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        System.out.println("线程2:" + test1.s1);
                        Thread.sleep(3000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值