118

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

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多个线程发送的内容?

4

2 回答 2

197

Hans Passant 的回答很好。但我想我会尝试用稍微简单一点的方式向任何遇到这个问题并且对 Java 不熟悉的人解释一下。开始..

java中的内存分为两种——堆和栈。堆是所有对象所在的地方,堆栈是线程工作的地方。每个线程都有自己的堆栈,并且不能访问彼此的堆栈。每个线程还有一个指向代码的指针,该指针指向它们当前正在运行的代码位。

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

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

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

于 2013-06-27T15:07:23.617 回答
67

会进入休眠状态吗?

不,运行一个线程不会影响其他线程,只要它们不是有意地相互同步。如果你有多个处理器内核,所有最近的机器都有,那么这些线程很可能同时执行。当您启动 5 个线程时,这种可能性会降低一些,因为您的机器可能没有足够的内核。操作系统被迫在它们之间进行选择,给它们每个运行时间。线程调度程序的工作。然后一个线程将不会处于“睡眠”状态,它只是暂停并等待线程调度程序给它一个运行的机会。它将在被调度程序中断的地方恢复。

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

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

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

于 2013-06-27T13:09:32.387 回答