簡體   English   中英

多線程

[英]Multi threading

我對多線程有一個想法,但我從未嘗試過。 因此,當我看到我的應用程序在工作時...我沒有看到任何擴展Thread的類來創建Thread 因此,當2個對象嘗試同時訪問變量時, synchronized使用synchronized關鍵字。我們使用synced來避免沖突。

例:

public class Test {

    private static int count = 0;

    public static synchronized void incrementCount() {
        count++;
    }
} 

如果測試類使用由對象然后是有意義的加synchronizedincrementcount() 但是,當你不延長ThreadRunnable那么有什么用書面synchronized

同步不適用於線程或Runnable,它用於由多個線程訪問的數據結構,以確保每個線程以不破壞其數據的方式訪問它們。 您自己的示例是一個簡單的例子,其中count以一種不是線程安全的方式遞增( 使用++,請參見此問題 ),因此需要鎖定以確保一次僅一個線程可以遞增它。

如果還有其他訪問count的代碼,則還需要同步它,以便可見count的更新。 如果您要做的只是增加一個計數器,那么使用java.util.concurrent.atomic.AtomicInteger類的類更有意義,並且您可以完全不使用synced關鍵字。

為了使同步有意義,它確實假定存在多個線程。 即使您自己的代碼沒有創建新的線程,在某些情況下也可能有多個線程在調用您的代碼(例如在servlet容器中,該容器管理線程池並為每個傳入請求分配線程)。

一個類不需要extend Threadimplements Runnable來將其方法標記為已同步,以防止多線程訪問

您的類可能是某個其他線程類的參數,並且該線程類可能具有多個實例。 為了提供強大的數據一致性,您已經保護了代碼和數據的關鍵部分。

只需更改您的代碼示例,如下所示。

我在對象級別而非類級別演示“已synchronized ”( static synchronized

class Test {
    private int count = 0;
    public void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        Test t = new Test();
        for ( int i=0; i<10; i++){
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

您的類Test已作為參數傳遞給線程MyRunnable 現在,您已經創建了多個線程實例。 在沒有synchronized關鍵字的情況下,輸出是不可預測的,如下所示。

java SynchronizedDemo
Count:2
Count:3
Count:2
Count:7
Count:6
Count:5
Count:4
Count:10
Count:9
Count:8

如果我改變

public void incrementCount() {

public synchronized void incrementCount() {

輸出為:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

另一方面,您已將您的方法設置為static synchronized That means lock is maintained at class level instead of object level.

請查看oracle文檔頁面以更好地理解。

缺少“ static synchronized ”的代碼演示

class Test {
    private static int count = 0;
    public static void incrementCount() {
        count++;
        System.out.println("Count:"+count);
    }
} 
class MyRunnable implements Runnable{
    private Test test = null;
    public MyRunnable(Test t){
        this.test = t; 
    }
    public void run(){
        test.incrementCount();
    }
}
public class SynchronizedDemo{
    public static void main(String args[]){
        for ( int i=0; i<10; i++){
            Test t = new Test();
            new Thread(new MyRunnable(t)).start();  
        }
    }
}

輸出:

Count:5
Count:4
Count:3
Count:2
Count:10
Count:9
Count:8
Count:7
Count:6

制作后

public static void incrementCount() {

ppublic static synchronized void incrementCount() {

輸出:

Count:1
Count:2
Count:3
Count:4
Count:5
Count:6
Count:7
Count:8
Count:9
Count:10

在此示例中,與之前不同,我們創建了10個不同的Test實例。

i++盡管看起來像一條指令,但實際上是多條指令:

  1. 將一個臨時變量設置為1+i
  2. 將變量i設置為臨時變量。

但是,假設執行i++的線程在步驟1之后被中斷,並且中斷線程也調用i++ 然后,會發生這種情況:

(假設i=1

  1. 原始線程:將臨時變量1+i設置為1+i2
  2. 中斷線程:將臨時變量2設置為i+1 ,也設置為2
  3. 中斷線程:i設置為臨時變量2。 現在i=2
  4. 原始線程:i設置為臨時變量1。 現在i=2

問題是,如果i++被調用兩次,則應該為3 ,而不是2


synchronized void將鎖定變量i直到整個void完成執行。 例如:

  1. 原始線程:將臨時變量1+i設置為1+i2 鎖定變量i
  2. 中斷線程:嘗試將臨時變量2設置為i+1 ,但由於變量i的鎖定而等待
  3. 原始線程:i設置為臨時變量1。 現在i=2 變量i現已解鎖。
  4. 中斷線程: “通知” i已經解鎖,因此它將臨時變量2設置為i+1 ,即3
  5. 中斷線程:i設置為3 ,這是預期行為。

synchronized void本質上是暫時鎖定變量,以避免混淆程序的執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM