繁体   English   中英

两个线程如何不能同时执行方法。 内部发生在代码中。

[英]How does two threads not able to execute method at the same time. Internally what happens in the code.

我有一个在某些类中同步定义的方法。

我们知道,如果我们创建一个同步的方法,那么一次只有一个线程能够执行任务。

此方法内部发生了什么?

其他线程如何无法执行相同任务以运行相同方法。

据我所知,join应用于该特定线程。 但是管道中的第二个线程如何知道任务是由第一个线程完成的。

告诉我我是否正确。

在Java语言中,每个对象都有一个称为Monitor的监视器,它基本上是一个锁。

此锁为对象方法(例如wait / signal / signalAll)提供动力,这些方法在每个对象上都可用。

当使用synced关键字时,在幕后发生的事情是编译器编写了获取监视器(锁)的代码,并在调用完成后将其释放。

如果该方法是静态的,则访问的Monitor是Class对象的Monitor。

您可以在此处阅读有关此关键字的更多信息: http : //docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

一个线程(第一个)获取对象的锁,另一个线程等待获取该对象的锁。

任务完成后,第一个线程使用notify()notifyAll()方法将通知发送到等待的线程。

此方法内部发生了什么?

当您说一个(实例级)方法已同步时,线程必须首先获取该对象的锁(即,首先保持该对象的监视器 )才能访问它。 只要一个线程持有 / 监视器 ,其他线程就无法访问它。 因为它们无法锁定物体(就像物体的门一样)。

其他线程如何无法执行相同任务以运行相同方法。

因为只要一个线程仍保持监视器,其他线程就会等待。 也就是说,它们本身无法访问监视器。因此,它们被阻止,将在该对象的等待集/队列中等待。

join应用于该特定线程。 但是管道中的第二个线程如何知道任务是由第一个线程完成的。

Join()确保在另一个线程上调用join()的线程等待,直到第二个线程完成其执行。

注意:调用join时,会在两个线程之间建立关系之前发生 这样,无论调用发生联接之前还是从联接返回之前, 发生的一切对于其他线程都是可见的。

编辑:

Assume ThreadA and ThreadB are two threads running concurrently.

ThreadA
{
 run(){
 //some statements;
  x=10; // assume x to be some shared variable
 ThreadB.join();
// here ThreadA sees the value of "x" as 20. The same applies to synchronized blocks.
// Suppose ThreadA is executing in a Synchronized block of Object A, then after ThreadA //exits the synchronized block, then other threads will "always" see the changes made by //ThreadA
// some other statements
}
}

ThreadB{
run(){
//some statements
 x=20;
}

检查: 发生之前

我们知道,如果我们创建一个同步的方法,那么一次只有一个线程能够执行任务。

不对! 两个或多个线程可以同时进入同一synchronized块。 而且,这不只是理论上的:它经常发生在精心设计的程序中。

这是两个或多个线程不能执行的操作:两个或多个线程不能同时在同一对象上同步。 如果要确保一次仅一个线程可以输入一个特定的方法(但是为什么呢?†),则需要编写该方法,以便对它的所有调用都可以在同一对象上同步。 如果它是静态方法,那很容易做到,因为:

class Foobar {
    synchronized MyType baz() { ... }
}

含义与此相同:

class Foobar {
    MyType baz () {
        synchronized (Foobar.class) { ... }
    }
}

静态同步方法的所有调用都在拥有该方法的类对象上同步。

[什么会阻止两个线程同时在同一个对象上同步]?

操作系统。 您想用于实际工作的任何JVM都使用本机线程来实现Java线程。 机线程是由对操作系统的调用创建和管理的线程。 特别是,它是操作系统的一部分,称为Scheduler 我不打算详细介绍操作系统调度程序的工作原理-(有关该主题的整本书都写过-)但它的工作是确定哪个线程可以运行,何时运行以及在哪个处理器上运行。

典型的调度程序使用队列来跟踪所有未实际运行的线程。 一个特殊的队列,即run queue ,包含准备运行但正在等待CPU运行的线程。 运行队列上的线程称为runnable 任何其他队列上的线程都会被阻塞 (即不允许运行),直到发生某种情况导致调度程序将其放回运行队列。

与Java 监视器相对应的操作系统对象(请参见@TheLostMind的答案)通常称为互斥体 对于每个互斥锁,都有一个被阻塞的线程队列,等待进入 本机线程通过调用操作系统进入互斥体。 如果互斥锁中已经有其他线程,这将使操作系统有机会暂停线程并将其添加到互斥锁的队列中。 当线程离开互斥锁时,这也是系统调用; 它使调度程序有机会从互斥量队列中选择一个线程,然后将其放回运行队列。

就像我说的那样,调度程序如何执行这些操作的细节太深了,以至于无法在这里讨论。 Google是您的朋友。


†不必担心哪些线程可以同时输入哪种方法。 而是担心哪些线程接触哪些数据 同步的目的是允许一个线程将您的数据暂时置于您不希望其他线程看到的状态。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM