多线程 - 多线程中使用静态方法存在线程安全的问题

Posted 放羊的牧码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程 - 多线程中使用静态方法存在线程安全的问题相关的知识,希望对你有一定的参考价值。

类的成员分两类,静态成员(static member)和实例成员(instance menber),静态成员属于类,实例成员则属于对象,即类的实例。

我们知道,静态字段和静态方法的调用都是通过类来调用的,静态方法不会对特定的实例操作,只能调用调用类中的其他属性和静态方法,不能调用类中的非静态属性和非静态方法。实例方法可以对特定的实例操作,既能访问静态属性和静态方法,也能访问实例属性和实例方法。

在多线程中使用静态方法是否有安全问题?这样看在静态方法中时候使用了静态成员。在多线程中使用一个静态方法的时候,每个线程共享一个静态字段,如果该静态方法不去操作一个静态变量,只在方法内部使用局部变量,则不会造成安全性问题。但是,如果该静态方法操作了一个静态字段,则需要在静态方法中采用互斥访问的方式来对其进行安全处理。

先来看没有线程安全问题的实例

public class Test 
	public static String hello(String str) 
		String tmp = "";
		tmp = tmp + str;
		return tmp;
	

上述示例中是线程安全的,这是因为在静态方法中声明了局部变量,每个线程在调用的时候,都会创建一份新的局部变量,比如这里的tmp,而不会共享一个存储单元。

以下是线程不安全的

public class Test 

	private static Test test;

	public static Test hello() 
		if(tets==null)
			Test=new Test();        
		return test;
	

这是因为在静态方法中又返回了静态变量,对于静态变量来说,类在加载的时候会占用同一个存储区,而每个线程都是公用这个存储区的,因此存在线程安全的问题。

划重点

静态方法和实例方法的区别是静态方法只能引用静态变量,静态方法通过类名来调用,实例方法通过对象实例来调用。

每个线程都有自己的线程栈,栈与线程同时创建,每一个虚拟机线程都有自己的程序计数器PC,在任何时刻,一个虚拟机线程只会执行一个方法的代码,这个方法称为该线程的当前方法,如果这个方法不是native的,程序计数器就保存虚拟机正在执行的字节码指令的地址。

线程调用方法的时候会创建栈帧,用于保存局部变量表和操作数栈以及指向该类常量池的引用。

静态方法虽然是同一个方法,但是不同线程在调用,程序计数器的值是不一样的,操作这两个线程不会相互影响(假设不存在访问共享变量的情况)​​​​​​​

因此在设计工具类的时候,对于没有使用到静态变量的静态工具类方法,是不需要加锁的(synchronized)。

在使用单例模式做工具类的时候,这个时候静态方法需要被加锁,这是因为所有的线程虽然有自己的方法栈,但是在方法栈中操作的是同一个对象的实体,所以需要进行加锁同步,来实现每个线程都需要等待锁的释放才能使用该对象的引用。

但是在多例模式做工具类的时候,是不需要加锁的,因为每个线程中有自己的方法栈,但是在方法栈中创建了独立的对象引用,可以看成是线程都是在自己的方法栈中操作局部的对象引用,因此这个时候不需要同步。

那么在静态方法中更新参数中传入的对象,存在多线程安全隐患么?

public class StaticMethod 

    // not exist any class attribute

    public static void setDataToPerson(Person person) 
        if(person.age > 60) 
            person.setLevel("OLD");
        
        

这个和是不是静态方法没有关系。取决于你操作的是这个 Person 对象是否同一个引用,如果两个线程访问的是同一个 Person 对象,那么你同时调用这个方法,当然的不是线程安全的;反之不是同一个对象,则线程安全。

补充说明

Q:为什么不直接在方法上加 synchronized?

A:因为会导致所有线程都需要加锁、释放锁,否则可以有一部分直接不经过锁。

以上是关于多线程 - 多线程中使用静态方法存在线程安全的问题的主要内容,如果未能解决你的问题,请参考以下文章

在多线程中使用静态方法是否有线程安全问题

java多线程之线程安全

再次理解多线程线程安全问题(理解java内存模型后)

在多线程中使用静态方法是否有线程安全问题

静态方法类被多线程调用安全性

静态方法类被多线程调用安全性