搜尋
首頁Javajava教程一個例子看懂Java中synchronized關鍵字到底怎麼用

本篇文章為大家帶來了關於java的相關知識,其中主要介紹了關於synchronized關鍵字的相關問題,包括了使用同步方法、使用同步語句或區塊以及什麼是同步、為什麼需要同步的相關內容,下面一起來看一下,希望對大家有幫助。

推薦學習:《java影片教學

在平時開發中,synchronized關鍵字常遇到,你知道synchronized怎麼用嗎?本文跟大家介紹一下。

我們有兩種方法可以使用同步:

  • 使用同步方法
  • 使用同步語句或區塊

使用同步方法

要讓方法同步,只需將synchronized關鍵字新增至其聲明:

public class SynchronizedDemo {

    private int i = 0;

    public synchronized void add() {
        i++;
    }

    public synchronized void del() {
        i--;
    }

    public synchronized int getValue() {
        return i;
    }
}

如上程式碼顯示,一共有三個同步方法:

  • add()
  • del()
  • getValue()

每個方法同一個物件同一時刻只會被調用一次,例如一個執行緒在呼叫add()時,其他執行緒都會被阻塞,直到第一個執行緒處理完add()方法。

使用同步語句或區塊

    public void del(int value){

        synchronized(this){
            this.i -= value;
        }
    }

如上程式碼,synchronized加在了一個{}程式碼前,這個就代表是一個同步程式碼區塊。

以上就是synchronized關鍵字兩種使用方法,以下我們來簡單的介紹一下同步相關的概念。

什麼是同步?

同步是一個控制多個執行緒存取任何共享資源的進程,可以避免不一致的結果。使用同步的主要目的是避免執行緒的不一致行為,防止執行緒幹擾。

在java中可以使用synchronized 關鍵字來實現同步的效果,synchronized只能應用於方法和區塊,不能應用於變數和類別。

為啥需要同步?

首先我們來看一段程式碼:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronizedDemo.increment();
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}

每當呼叫increment()方法時計算值都會加1:

調用2次就會加2,呼叫3次就會加3,呼叫4次就會加4:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        synchronizedDemo.increment();
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}

現在我們擴充一下上面的例子,建立一個線程去呼叫10次increment()方法:

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
        Thread thread = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                synchronizedDemo.increment();
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}

此時計算的結果正如我們預期的那樣,結果為10.

##這是單線程的情況,一切都是如此的美好,但事實真的如此嗎?如果是多執行緒環境,會是什麼樣的?

下面我們來示範多執行緒的情況!

public class SynchronizedDemo {

    int i;

    public void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}

如上程式碼,我們建立了兩個執行緒thread1 和thread2,每個執行緒呼叫1000次increment(),理論上最終列印的值應該是

2000#,因為thread1呼叫increment ()1000次後值會變成1000,thread2呼叫increment()1000次後值會變成2000.

我們執行一下,看看結果:

#結果和我們想的不一樣,小於2000,我們再執行:

#結果還是小於2000.

這是為什麼呢?

因為多執行緒支援並行處理,因此,兩個執行緒總是有可能同時取得計數器的值,因此都得到相同的計數器值,所以在這種情況下,不是遞增計數器的值兩次,只增加一次。

那麼,如何避免這種情況呢?

使用 synchronized 關鍵字即可解決。

我們只需要將increment()方法加上synchronized就可以了:

public class SynchronizedDemo {

    int i;

    public synchronized void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 1000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}

這個時候我們再執行一下:

#################################################################################################可以看到,值為2000.######我們把計算次數提高到10000次:###
public class SynchronizedDemo {

    int i;

    public synchronized void increment() {
        i++;
    }

    public static void main(String[] args) {
        SynchronizedDemo synchronizedDemo = new SynchronizedDemo();

        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 10000; i++) {
                synchronizedDemo.increment();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 10000; i++) {
                synchronizedDemo.increment();
            }
        });

        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("计算值为:" + synchronizedDemo.i);
    }
}
###執行結果為:###############可以看出,一個小小的synchronized竟然那麼簡單的就解決了這個問題。 ###

這個背後的原理就是線程1執行increment()方法時,因為有synchronized,所以會自動將此方法加鎖,而此時只有線程1擁有這把鎖,其他線程只能等待,直到線程1釋放這把鎖,線程2才能參與呼叫。

同理,當線程2去調用increment()時,線程2拿到鎖,線程1進入等待,直到線程2釋放鎖,就這樣,直到計算完畢,在此過程中,不會出現計算錯誤的情況。

總結

  • synchronized 關鍵字是使區塊或方法同步的唯一方法。
  • synchronized 關鍵字提供了鎖定的特性,它確保執行緒之間不會出現競爭條件。被鎖定後,執行緒只能從主記憶體讀取數據,讀取資料後,它會刷新寫入操作,然後才能釋放鎖定。
  • synchronized 關鍵字也有助於避免程式語句的重新排序。

推薦學習:《java影片教學

以上是一個例子看懂Java中synchronized關鍵字到底怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:脚本之家。如有侵權,請聯絡admin@php.cn刪除
Java仍然是基於新功能的好語言嗎?Java仍然是基於新功能的好語言嗎?May 12, 2025 am 12:12 AM

Javaremainsagoodlanguageduetoitscontinuousevolutionandrobustecosystem.1)Lambdaexpressionsenhancecodereadabilityandenablefunctionalprogramming.2)Streamsallowforefficientdataprocessing,particularlywithlargedatasets.3)ThemodularsystemintroducedinJava9im

是什麼使Java很棒?關鍵特徵和好處是什麼使Java很棒?關鍵特徵和好處May 12, 2025 am 12:11 AM

Javaisgreatduetoitsplatformindependence,robustOOPsupport,extensivelibraries,andstrongcommunity.1)PlatformindependenceviaJVMallowscodetorunonvariousplatforms.2)OOPfeatureslikeencapsulation,inheritance,andpolymorphismenablemodularandscalablecode.3)Rich

前5個Java功能:示例和解釋前5個Java功能:示例和解釋May 12, 2025 am 12:09 AM

Java的五大特色是多態性、Lambda表達式、StreamsAPI、泛型和異常處理。 1.多態性讓不同類的對象可以作為共同基類的對象使用。 2.Lambda表達式使代碼更簡潔,特別適合處理集合和流。 3.StreamsAPI高效處理大數據集,支持聲明式操作。 4.泛型提供類型安全和重用性,編譯時捕獲類型錯誤。 5.異常處理幫助優雅處理錯誤,編寫可靠軟件。

Java的最高功能如何影響性能和可伸縮性?Java的最高功能如何影響性能和可伸縮性?May 12, 2025 am 12:08 AM

java'stopfeatureSnificallyenhanceItsperformanCandScalability.1)對象 - 方向clincipleslike-polymormormormormormormormormormormormorableableflexibleandscalablecode.2)garbageCollectionAutectionAutoctionAutoctionAutoctionAutoctionAutoctionAutoMenateMememorymanateMmanateMmanateMmanagementButCancausElatemention.3)

JVM內部:深入Java虛擬機JVM內部:深入Java虛擬機May 12, 2025 am 12:07 AM

JVM的核心組件包括ClassLoader、RuntimeDataArea和ExecutionEngine。 1)ClassLoader負責加載、鏈接和初始化類和接口。 2)RuntimeDataArea包含MethodArea、Heap、Stack、PCRegister和NativeMethodStacks。 3)ExecutionEngine由Interpreter、JITCompiler和GarbageCollector組成,負責bytecode的執行和優化。

什麼是使Java安全安全的功能?什麼是使Java安全安全的功能?May 11, 2025 am 12:07 AM

Java'ssafetyandsecurityarebolsteredby:1)strongtyping,whichpreventstype-relatederrors;2)automaticmemorymanagementviagarbagecollection,reducingmemory-relatedvulnerabilities;3)sandboxing,isolatingcodefromthesystem;and4)robustexceptionhandling,ensuringgr

必不可少的Java功能:增強您的編碼技巧必不可少的Java功能:增強您的編碼技巧May 11, 2025 am 12:07 AM

Javaoffersseveralkeyfeaturesthatenhancecodingskills:1)對象 - 方向 - 方向上的allowslowsmodelowsmodelingreal-worldentities

JVM最完整的指南JVM最完整的指南May 11, 2025 am 12:06 AM

thejvmisacrucialcomponentthatrunsjavacodebytranslatingitolachine特定結構,影響性能,安全性和便攜性。 1)theclassloaderloader,links andinitializesClasses.2)theexecutionEngineExecutionEngineExecutionEngineExecuteNexeCuteByteCuteByteCuteByTecuteByteCuteByteCuteBytecuteBytecuteByteCoDeinintolachineinstructionsions.3)Memo.3)Memo

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境