ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

搞懂volatile(java线程和unix线程)(一)

2022-02-27 15:32:38  阅读:179  来源: 互联网

标签:java attr thread 线程 attrs pthread 搞懂


        写在开头的地方,本文是笔者的理解,不一定正确,但属于是自己较为深入的学习所得,在此进行分享学习。

        话不多说,开搞, 一些volatile的基础知识我就不说了,我们先来看两类代码java和c++的

        先上java的代码,非常简单

public class Test_1 {
    private static int a = 0;
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println("等待thread-2改变对a的数值");
            while (0 == a) {
            }
            System.out.println("感受到数值的改变" + a);
        }, "thread-1").start();

        new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("thread-2改变对a的数值");
            a = 1;
        }, "thread-2").start();
    }
}

因为静态字段a没有被volatile字段修饰,所以「感受到数值的改变」这句话不会被输出。

实际情况也的确如此。

那么我们再来看c++的代码,会涉及到一些unix线程编程,但不关键

int a = 0;
void* thread1_do(void* arg){
    INFO_PRINT("等待thread-2改变对a的数值\n");
    while (0 == a){}
    INFO_PRINT("感受到数值的改变\n");
    return NULL;
}
void* thread2_do(void* arg){
    INFO_PRINT("thread-2改变对a的数值\n");
    a = 1;
    return NULL;
}
int main(){
    pthread_t       tid_1[1];
    pthread_t       tid_2[1];

    pthread_attr_t  attrs_1[1];
    pthread_attr_t  attrs_2[1];

    pthread_attr_init(attrs_1);
    pthread_attr_setdetachstate(attrs_1,PTHREAD_CREATE_DETACHED);

    pthread_attr_init(attrs_2);
    pthread_attr_setdetachstate(attrs_2,PTHREAD_CREATE_DETACHED);

    pthread_create(tid_1, attrs_1, thread1_do, NULL);
    pthread_create(tid_2, attrs_2, thread2_do, NULL);

    pthread_attr_destroy(attrs_1);
    pthread_attr_destroy(attrs_2);
    sleep(1);
}

会发现,同样是局部变量的a,同样的线程逻辑。

但是却发现结果不同,这是为什么呢???

那么我们的第一个问题

问题一 为什么java线程修改全局变量是不可见的,而c++(unix)线程修改全局变量却是可见的。

我们先来回答后者,使用clion自带的lldb,我们debug可以看到反汇编

 

这句汇编很简单吧,简单的赋值操作,也就是说,是直接修改内存的值,所以c++线程修改全局变量是可见的。

那么我们再来看看,为什么java线程修改全局变量是不可见的,讲道理,java基于jvm运行,jvm是c++写的,也应该可见啊。其实用理论知识证明也很容易,

证明:因为java线程是运行在虚拟机栈中的,而虚拟机栈是不共享的。

           因为java线程是面向对象的形式出现的,且java的线程实现了自己的一套JMM模型。

           因为java虚拟机栈中存在栈帧,也就是在java语言进行a = 1时做的操作是如何的,通过jclasslib插件我们可以很清晰看到

icounst_1: 将常量1压入操作数栈

putstatic: 将操作数栈中顶端第一个值弹出栈对a进行赋值

可以发现,这两条指令都是在虚拟机栈中进行的,而虚拟机栈又不是共享的,所以a的改变并不会同步到方法区的引用中去。

问题二 为什么java中全局变量加了volatile关键字,字段就有了「可见性」

这个就留到之后再讲吧,其实网上资料也挺全的了,内存屏障啊,happens-before原则之类的,但是大多都还是理论,我看看之后有空把源码翻出来整理整理吧。本文到此结束。 

后记:对于问题2,putstatic,getstatic这类字节码中在bytecodeparse解析中会有一个判断,is_volatile()的方法,有兴趣可以自己先看看。

 

标签:java,attr,thread,线程,attrs,pthread,搞懂
来源: https://blog.csdn.net/weixin_42258418/article/details/123163698

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有