11

静态方法、实例化方法与线程安全

 4 years ago
source link: http://www.linkedkeeper.com/1640.html?
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.
neoserver,ios ssh client
静态方法、实例化方法与线程安全
10余年资深架构经验,对高性能网关、多线程、NIO、HTTP/TCP 长连接等技术有较深的研究与实战经验,主导过百亿级网关系统和亿级交易系统的设计与实现,目前主要专注于微服务架构、分布式技术。

静态方法与实例化方法

大家在使用 Java 的时候,一定都有一个共识,少使用静态方法,要多使用实例化方法,这样会更稳妥。

首先,先来澄清一下对静态方法和实例化方法的误解:

1、静态方法常驻内存,实例方法不是

事实上,静态方法和实例方法都是在第一次被调用时被加载,在加载时机和占用内存上是一样的。

2、静态方法分配在堆上,实例化方法分配在堆栈上

事实上,所有方法都不会在堆栈上分配内存。字段是用来存储每个实例对象的信息的,所以字段会占用内存,每个实例对象都会在内存中有一份所有字段的拷贝。但方法不一样,无论有多少个实例对象,它的方法的代码都是一样的。因此无论是 static 还是 non-static 方法,都只存在一份代码,也只占用一份内存。

从编程思想上,单例的出现并不是为了解决什么高深复杂的性能之类的问题,它只是面向对象的一种体现,可以继承拓展,可以实现接口,比较灵活。静态类更像是一个方法的集合,提供全局的访问而已, 比如大多数的 Util。

如果我们全部用静态方法,不用实例化方法,不是一样能实现功能吗?是的,没错,但是你的代码是基于对象,而不是面向对象的,因为面向对象的继承和多态,都是非静态方法。

静态方法与线程安全

静态方法如果没有使用静态变量,则没有线程安全问题。

如果 Java 在执行静态方法时,使用静态变量,同时类的函数设计时使用到了静态数据,最好在调用函数时使用 synchronized 关键字,否则会导致数据的不一致行。

实例化方法与线程安全

实现一个只能实例化一次的类,即单例模式(Singleton),在 Java 中,单例对象能保证在一个 JVM 中只有一个实例存在。

JVM 在每一个线程启动的时候,会为当前线程创建一个栈,每一个栈的数据都是私有的,别的栈不能访问,所以线程之间栈的数据是独立的。

方法被编译成指令,放在方法区中,一个类的一个方法在 JVM 里就是一块内存里保存的指令。

linkedkeeper0_7851c9d5-b488-420f-9a3a-a1cec5cac7ed.jpg

每执行一个方法都是在栈中压入一个栈帧,栈帧中存储局部变量表、操作数栈、动态链接、方法接口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在 JVM 栈中入栈出栈的过程。

linkedkeeper0_ae3468c1-0a74-4a90-b9ec-e6bd809544c6.jpg

两个线程同时执行单例对象上的同一方法时,因为方法本身只是方法区的一块内存,两个线程是可以同时执行方法对应的指令,而方法内存的局部变量,操作数等都是保存在线程内部的私有栈中,不共享,所以完全可以同时调用。

单例模式中唯一实例为什么要用静态?

因为程序调用类中方法只有两种方式,一是创建类的一个对象,用该对象去调用类中方法;二是使用类名直接调用类中方法,格式 类名::方法名();单例模式将构造函数私有化后,第一种情况就不能用,只能使用第二种方法。

成员变量与线程安全

静态成员变量

静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故无论是单例或非单例,都是线程不安全的。

实例成员变量

实例变量为对象实例私有,在虚拟机的堆 heap 中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全(如,springmvc controller 是单例的,非线程安全的);如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全(如,struts2 action 默认是非单例的,每次请求在 heap 中 new 新的 action 实例,故 struts2 action 可以用实例成员变量)。即单例模式(只有一个对象实例 singleton 存在)线程非安全,非单例线程安全。

局部变量

每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。

Reference

https://www.jianshu.com/p/298297baee7a

https://www.jianshu.com/p/30e174b4fa9c

https://blog.csdn.net/qq_20906903/article/details/80560987

转载请并标注: “本文转载自 linkedkeeper.com (文/张松然)”  ©著作权归作者所有

linkedkeeper0_34ac9c18-67c9-447d-a6e7-1db1f39396ae.jpg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK