Java多線程基礎篇(03)-synchronized關鍵字

1.引言

    基本上全部的併發模式再解決線程衝突的時候,都是採用序列化訪問共享資源的方案。這意味着在給定時刻只容許一個任務訪問共享資源。一般這是經過在代碼前面添加一條鎖語句來實現的,這就使得在一段時間內只有一個任務能夠運行這段代碼。由於鎖語句產生了一種互相排斥的效果,鎖着這種機制經常被稱爲互斥量。java

    Java以提供關鍵字synchronized的形式,爲防止資源衝突提供了內置支持。當任務要執行被synchronized關鍵字保護的代碼片斷的時候,它將檢查鎖是否可用,而後獲取鎖,執行代碼,釋放鎖編程

    共享資源通常是以對象形式存在的內存片斷,但也能夠是文件、輸入/輸出端口,或者是打印機設備。要控制對共享資源的訪問,得先把它包裝進一個對象。而後把全部要訪問這個資源的方法標記爲synchronized。若是某個任務處於一個對標記爲synchronized方法的調用中,那麼在這個線程從該方法返回以前,其餘全部要調用類中任何標記synchronized方法的線程都會被阻塞。多線程

2.synchronized原理

    在Java中,每個對象有且僅有一個同步鎖。這也意味着,同步鎖依賴對象而存在。當咱們調用某個對象的synchronized修飾的方法時,就獲取了該對象的同步鎖。例如synchronized(obj)方法就獲取了obj這個對象的同步鎖。併發

    不一樣線程對同步鎖的訪問是互斥的。也就是說,在某一個時刻,對象的同步鎖只能被一個線程獲取到!其餘要獲取該鎖的線程都會被阻塞。知道線程釋放了該鎖,其餘線程才能去獲取同步鎖,而後執行代碼塊。詳細的synchronized工做原理請見博客:synchronized實現原理ide

3.synchronized基本用法

    synchronized語句計算一個對象引用,試圖對該對象完成鎖操做,而且在完成所操做前中止處理。當鎖操做完成,synchronized語句體獲得執行。當語句體執行完畢(不管正常與否),解鎖操做自動執行。synchronized常常與方法連用。函數

public synchronized void function(){
    //保護函數
}

    一種比較好的辦法是,若是某個變量由一個線程賦值,並由別的線程引用或賦值,那麼全部對該變量的訪問都必須在某個synchronized語句或者synchronized方法內,oop

synchronized(this){
    //保護代碼塊
}

    有了synchronized關鍵字,多線程程序的運行結果將變得能夠控制。synchronized關鍵字用於保護共享數據。因此編程時分清共享數據很重要this

4.synchronized代碼演示

4.1 synchronized爲對象實例加鎖

class MyRunable implements Runnable {
    
    @Override
    public void run() {
        synchronized(this) {
            try {  
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100); // 休眠100ms
                    System.out.println(Thread.currentThread().getName() + " loop " + i);  
                }
            } catch (InterruptedException ie) {  
            }
        }  
    }
}

public class Demo1_1 {

    public static void main(String[] args) {  
        Runnable demo = new MyRunable();     
        Thread t1 = new Thread(demo, "t1");
        Thread t2 = new Thread(demo, "t2");
        t1.start();
        t2.start();
   } 
}

運行結果:spa

t1 loop 0
t1 loop 1
t1 loop 2
t1 loop 3
t1 loop 4
t2 loop 0
t2 loop 1
t2 loop 2
t2 loop 3
t2 loop 4

結果說明:.net

run()方法中存在synchronized(this)代碼塊,並且t1和t2都是基於Runnable對象建立的線程。這就意味着,咱們能夠將synchronized(this)中的this看做是Runnable對象;所以t1和t2共享demo對象的同步鎖。因此,當一個線程運行的時候,另一個線程必須等待「運行中的線程」釋放同步鎖以後才能運行。特此說明:synchronized(this)中的this是指當前的類對象,即synchronized(this)所在的類對應的當前對象。它的做用是獲取「當前對象的同步鎖」。

4.2 synchronized爲方法加鎖

    synchronized方法是用synchronized修飾的方法,具體示例這裏不給出了,有興趣的童鞋,能夠參照4.1給方法加上synchronized修飾。

相關文章
相關標籤/搜索