

局部变量是线程安全的,原因是什么?
source link: https://juejin.cn/post/7083744871172800542
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

局部变量是线程安全的,原因是什么?
本文分享自华为云社区《【高并发】为什么局部变量是线程安全的?》,作者:冰河。
多个线程同时访问共享变量时,会导致并发问题。那么,如果将变量放在方法内部,是不是还会存在并发问题呢?如果不存在并发问题,那么为什么不会存在并发问题呢?
著名的斐波那契数列
记得上学的时候,我们都会遇到这样一种题目,打印斐波那契数列。斐波那契数列是这样的一个数列:1、1、2、3、5、8、13、21、34…,也就是说第1项和第2项是1,从第3项开始,每一项都等于前2项之和。我们可以使用下面的代码来生成斐波那契数列。
//生成斐波那契数列
public int[] fibonacci(int n){
//存放结果的数组
int[] result = new int[n];
//数组的第1项和第2项为1
result[0] = result[1] = 1;
//计算第3项到第n项
for(int i = 2; i < n; i++){
result[i] = result[i-2] + result[i-1];
}
return result;
}
复制代码
假设此时有很多个线程同时调用fibonacci()方法来生成斐波那契数列,对于方法中的局部变量result,会不会存在线程安全的问题呢?答案是:不会!!
接下来,我们就深入分析下为什么局部变量不会存在线程安全的问题!
方法是如何被执行的?
我们以下面的三行代码为例。
int x = 5;
int[] y = fibonacci(x);
int[] z = y;
复制代码
当我们调用fibonacci(x)时,CPU要先找到fibonacci()方法的地址,然后跳转到这个地址去执行代码,执行完毕后,需要返回并找到调用方法的下一条语句的地址,也就是int[] z = y的地址,再跳到这个地址去执行。我们可以将这个过程简化成下图所示。
这里需要注意的是:CPU会通过堆栈寄存器找到调用方法的参数和返回地址。
例如,有三个方法A、B、C,调用关系为A调用B,B调用C。在运行时,会构建出相应的调用栈,我们可以用下图简单的表示这个调用栈。
每个方法在调用栈里都会有自己独立的栈帧,每个栈帧里都有对应方法需要的参数和返回地址。当调用方法时,会创建新的栈帧,并压入调用栈;当方法返回时,对应的栈帧就会被自动弹出。
我们可以这样说:栈帧是在调用方法时创建,方法返回时“消亡”。
局部变量存放在哪里?
局部变量的作用域在方法内部,当方法执行完,局部变量也就没用了。可以这么说,方法返回时,局部变量也就“消亡”了。此时,我们会联想到调用栈的栈帧。没错,**局部变量就是存放在调用栈里的。**此时,我们可以将方法的调用栈用下图表示。
很多人都知道,局部变量会存放在栈里。如果一个变量需要跨越方法的边界,就必须创建在堆里。
调用栈与线程
两个线程就可以同时用不同的参数调用相同的方法。**那么问题来了,调用栈和线程之间是什么关系呢?答案是:每个线程都有自己独立的调用栈。**我们可以使用下图来简单的表示这种关系。
此时,我们在看下文中开头的问题:Java方法内部的局部变量是否存在并发问题?答案是不存在并发问题!因为每个线程都有自己的调用栈,局部变量保存在线程各自的调用栈里,不会共享,自然也就不存在并发问题。
方法里的局部变量,因为不会和其他线程共享,所以不会存在并发问题。这种解决问题的技术也叫做线程封闭。官方的解释为:仅在单线程内访问数据。由于不存在共享,所以即使不设置同步,也不会出现并发问题!
Recommend
-
39
-
53
我们在编程中,无时无刻地都在于方法打交道,而在方法中,我们很难不使用局部变量,比如我们有下面的这样一段很简单的代码 public void dump() { String localName; System.out.println("dump l...
-
52
局部变量 在C语言中写在{}中或者函数中或者函数的形参, 就是局部变量 Go语言中的局部变量和C语言一样 全局变量 在C语言中写在函数外面的就是全局变量 Go语言中...
-
60
byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8417 本文可全文转载,个人网站无需授权,只要保留原作者、出处以及文中链接即可,任何网站均可摘要...
-
24
一、C/C++报错?Golang通过? 我们先看一段代码 package main func foo(arg_val int)(*int) { var foo_val int = 11; return &foo_val; } func main() { main_val := foo(666) println(*mai...
-
35
哈喽,大家好,磊哥的性能优化篇又来了! 其实写这个性能优化类的文章初衷也很简单,第一:目前市面上没有太好的关于性能优化的系列文章,包括一些付费的文章;第二:我需要写一些和别人不同的知识点,比如大家都去写 SpringBoot...
-
12
JAVA 10 新特性 - 局部变量推断 boyizmen 2020-04-14 Java 10 添加了一个非常重...
-
11
我在《栈又溢出了》 一文中记录了一个奇怪的栈溢出问题。虽然解决了,但是总感觉哪里不太合理。我想,vs 一定有一个合理的设置。一起折腾起来吧!...
-
11
C语言陷阱与技巧第1节,C语言函数中的局部变量作用范围是整个函数吗? 发表于...
-
6
python | 多线程下局部变量会改变吗 记得这样一句话。 在 Python 中,线程在执行过程中的状态信息(包括局部变量和参数)会被...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK