您现在的位置是:首页 > 正文

证明static 关键字并不能保证线程可见性

2024-02-01 00:20:02阅读 2

1.static : 标识这个属性是实例共享的。(也可以称作类变量)

2.volatile:标记该属性是易变的,被修饰的属性被修改后,别的线程每当用到该属性都要重新去读取。

线程运行时会将用到的数据拷贝一份,放到自己的线程栈中,volatile会让该线程修改数据后写回原数据,并通知别的线程重新读取。

疑惑:static 修饰变量是类变量,被修改后别的线程也“应该”能读取到,是不是也具有线程可见性?

证明:代码如下

package highconcurrency;

/**
 * <b>测试volatile关键字</b></br>
 *
 * @Company 子虚</ br>
 * @Version V1.0
 * @Author 花月
 * @Date 2020/8/13 8:46
 */
public class TestVolatile {
    public static void main(String[] args) {
        MyData myData = new MyData();
        new Thread(() -> {
            System.out.println("线程启动a值为:"+myData.a);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.changeA();
            System.out.println("线程结束a值为:"+myData.a);
        }).start();
        //如果读取不到最新a值这里会死循环
        while (myData.a==0){
            //循环里不能写代码,不然不增加volatile也能读取最新的a值,猜想这里的操作导致while循环重新读取了a的值
            /* try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
//            System.out.println(myData.a);
        }
        System.out.println("a的值改变,并且被主线程看到");
    }
}

class MyData{
    //设置 volatile,static,和不加关键字。只有volatile能达到线程可见性。
//    static int a = 0;
    volatile int a = 0;
//    int a = 0;

    void changeA(){
        a = 10;
    }
}

当a属性不加static和volatile修饰时执行结果:

增加volatile关键字执行结果:

增加static修饰执行结果:

结论:

只有volatile具有线程可见性。

测试的时候while循环里不能写代码,写代码会导致不加volatile修饰出现和加volatile一样的效果.可能循环里的操作,导致重新读取a得值了。哪位大佬清楚这里原因请告知,不胜感激。

 

网站文章

  • 7-3 类的定义和使用

    7-3 类的定义和使用

    定义一个日期类Date,内有数据成员year、month和day,分别代表年、月、日,并若干有成员函数:构造函数用于初始化数据成员,isLeap函数用于闰年的判断。编写主函数:创建日期对象,判断该年是否是闰年。

    2024-02-01 00:19:34
  • react中popover弹窗_移动端控件(三)-气泡(Popover)

    react中popover弹窗_移动端控件(三)-气泡(Popover)

    什么是气泡(Popover/弹出框/弹出式气泡)弹出框(Popovers)是一个瞬态视图,当您点击某个控件或区域时,它会显示在屏幕上其他内容的上方。通常,弹出窗口包括指向其出现位置的箭头。Popove...

    2024-02-01 00:19:28
  • 使用freemarker按模板导出带表格word文档

    使用freemarker按模板导出带表格word文档

    一.制作模板 1.将word文档制作成以下样式,需要替换的内容放占位符,并按照占位符名字替换数据。表格里,使用RR.XXX的形式的占位符。RR表示当前行对象的名字,XXX相当于对象的属性名。写后台的时候,根据这些名将数据存为map,即名字为键值。例子如下: 2.将word另存为xml格式,这里因为项目需要,我将word保存为.xml 2003。然后将xml文件以标签的形式打开,这里我使...

    2024-02-01 00:18:52
  • Spring框架注解开发——史上最清晰总结Aop原理(超详细)

    Spring框架注解开发——史上最清晰总结Aop原理(超详细)

    Aop

    2024-02-01 00:18:43
  • socket协议 & socket函数

    Socket协议的形象描述  socket的英文原义是“孔”或“插座”。在这里作为4BDS UNIX的进程通信机制,取后一种意思。socket非常类似于电话插座。以一个国家级电话网为例。电话的通话双方相当于相互通信的2个进程,区号是它的网络地址;区内一个单位的交换机相当于一台主机,主机分配给每个用户的局内号码相当于socket号。任何用户在通话之前,首先要占有一部电话机,...

    2024-02-01 00:18:36
  • 【MySQL】表的增删查改(初阶)

    【MySQL】表的增删查改(初阶)

    单行数据+全列插入;多行数据+指定列插入;一次插入多个数据;全列查询;指定列查询;查询字段为表达式;别名 AS;去重查询 DISTINCT;排序查询 ORDER BY;条件查询 WHERE;时间的插入与查询;模糊查询;NULL的查询;分页查询LIMIT;修改;删除

    2024-02-01 00:18:09
  • 小白聊智慧制造之十四:一文轻松读懂边缘计算

    小白聊智慧制造之十四:一文轻松读懂边缘计算

    大概很多人都有这样的经历:不小心,手被火烧或被开水烫了,人会立即移开自己的手,这个反应是人的自组织条件反射反应。我们假设一下,如果我们的手被火烧或被开水烫由我们大脑根据汇集的信息做反应决定,再采取行动的话,那会是一个什么样的场景? 假设我们把人的条件反射标记为边缘计算,把人的大脑的反应标记为云计算的话,那么我们就可以浅显而又深刻地了解边缘计算和云计算的区别。 一、什么是边缘计算 边缘计算...

    2024-02-01 00:17:57
  • 获取两个Set集合的并集、差集、交集、补集、对称差集

    代码:public class Test { public static void main(String[] args) { Set<String> a = new HashSe...

    2024-02-01 00:17:50
  • 【GO】入门踩坑记录

    【GO】入门踩坑记录

    目录 1. 编译器 2. PROXY代理 设置 2.1. 设置proxy源 2.2. 处理冲突 3. go工程 3.1. 目录结构 3.2. 处理 github库 依赖 4. 编译 4.1. linu...

    2024-02-01 00:17:21
  • shell 月末

    shell 月末TX_DATE='2020-05-29'MON_LAST_DAY=$(date -d "$(date -d "$(date -d ${TX_DATE} +%Y-%m-01) 1 mon...

    2024-02-01 00:17:15