Java多线程环境中的静态方法行为


114

有一个简单的愚蠢问题困扰着我,并在我脑海中提出了几个论点。我想排除所有关于以下问题的疑问。

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

假设有五个线程同时执行一个调用Clstest.testStaticMethod("arg-n")

线程1调用Clstest.testStaticMethod("arg-1")

当线程1位于第1节中时,线程2调用Clstest.testStaticMethod("arg-2")

那么线程1将会发生什么?会进入睡眠状态吗?

当线程1获得机会时,它将从暂停的第1节继续执行吗?

当所有五个线程共享一个Clstest.testStaticMethod相同的Clstest.testStaticMethod线程时,如何处理?

有可能互换inFileStr多个线程发送的消息吗?


您定位的语言是什么?
ΩmegaMan

3
@ OmegaMan:它是Java
namalfernandolk

Answers:


192

汉斯·帕桑特(Hans Passant)的回答很好。但是我想我会尝试为遇到此问题并且对Java陌生的任何人进行更简单的解释。开始..

Java中的内存分为两种-堆和栈。堆是所有对象生存的地方,而堆栈是线程进行工作的地方。每个线程都有自己的堆栈,不能访问其他堆栈。每个线程还有一个指向代码的指针,该指针指向它们当前正在运行的代码位。

当线程开始运行新方法时,它将参数和局部变量保存在该方法自己的堆栈中。其中一些值可能是指向堆上对象的指针。如果两个线程同时运行同一方法,则它们的代码指针都指向该方法,并且它们的堆栈上有它们自己的参数和局部变量的副本。只有当堆栈中的内容指向堆上的相同对象时,它们才会互相干扰。在这种情况下,可能会发生各种各样的事情。但是正如汉斯指出的那样,字符串是不可变的(无法更改),因此,如果这是唯一“共享”的对象,那么我们是安全的。

如此多的线程可以运行相同的方法。它们可能不会同时运行-这取决于您的计算机上有多少个内核,因为JVM将Java线程映射到调度到硬件线程的OS线程。因此,在不使用复杂同步机制的情况下,您几乎无法控制这些线程的交错方式。

请注意,睡眠是线程对其自身所做的事情。


3
因此,在多核处理器环境中,可能有多个线程同时运行相同的代码,不是吗?在单处理器环境中,给定时间只有一个线程在运行。(多个线程在其中共享时间。)因此,当调度的线程给了从当前执行线程(A)到线程(B)的机会时,线程(A)如何从暂停的位置恢复?我的意思是它怎么知道简历的要点?是否因为“每个线程在代码中都有一个指向它们当前正在运行的代码的指针”?如你所说?
namalfernandolk

6
知道了 只是为了澄清一些要点-首先,如何调度线程不在Java的控制范围内。我在这里谈论Sun的Hotspot JVM。JVM将Java线程映射到OS线程,然后OS决定运行哪些线程。就像您说的那样,在一台单核计算机上,该操作系统一次只能运行一个,而在多核计算机上,它可能一次运行多个。其次,线程并没有真正知道它何时暂停,它所拥有的唯一信息就是程序指针(指向代码的指针)和堆栈,它们按原样保存和恢复。
selig 2013年

因此,当线程使用变量超出其本地范围时发生线程间干扰,例如,一个线程在另一个线程将那是该变量(或指向该变量的指针)拉到自己的堆栈上之前更新了变量的值?这是正确的理解吗?
hariszhr '16

2
确切地说,当线程共享堆上的内容(非本地)时,干扰只会发生并且可能发生,但不一定会发生。有几种不同的发生干扰的方式,这取决于代码不同部分之间的依赖性。我不确定您的示例,因为缺少一些详细信息。也许您是在指一个潜在的问题,线程A和B都读取一个共享值,然后都基于读取的值对其进行更新。这是一场数据竞赛。
selig

1
@selig,如果我有一个仅具有实例方法的类,例如服务类,并且它是单例,那么我不必担心一次执行多个实例方法的多个线程,因为该服务类不持有任何状态,而状态仅当class具有实例变量时才存在。我的理解正确吗?
Yug Singh,

67

会进入睡眠状态吗?

不,运行一个线程不会影响其他线程,只要它们没有故意彼此同步即可。如果您拥有多个处理器核心,那么所有最近使用的计算机都将拥有这些处理器核心,那么这些线程可能会在同一时间执行。当您启动5个线程时,这的可能性会降低,因为您的计算机可能没有足够的内核。操作系统被迫在它们之间进行选择,从而给它们每个运行时间。线程调度程序的工作。这样一来,线程将不会处于“睡眠”状态,只需将其暂停并等待线程调度程序为其运行即可。它会在调度程序中断的地方继续。

是否有可能互换多个线程发送的inFileStr?

没有这种可能性,线程具有自己的堆栈,因此任何方法参数和局部变量对于每个线程都是唯一的。此外,使用字符串可确保这些线程不会相互干扰,因为字符串是不可变的。

如果参数是对另一种可变对象的引用,则无法保证。或者方法本身使用静态变量还是对堆上对象的引用。当线程修改对象而另一个线程读取它时,需要进行同步。C#语言中的lock关键字是实现此类所需同步的样板方式。该方法是静态的事实并不意味着永远不需要这种同步。由于您不必担心线程访问同一对象(共享对象),因此可能性较小。


3
糟糕,从未见过[java]标签。足够近。
汉斯·帕桑

我忘了在发布时添加。我的错。:)。无论如何,谢谢您的回答。这非常有帮助。
namalfernandolk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.