簡體   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