一張圖講解對象鎖和關鍵字synchronized修飾方法

每一個對象在出生的時候就有一把鑰匙(監視器Monitor),那麼被synchronized 修飾的方法至關於給方法加了一個鎖,這個方法就能夠進行同步,在多線程的時候,不會出現線程安全問題。java

注:Monitor是 Java中用以實現線程之間的互斥與協做的主要手段,它能夠當作是對象或者 Class的鎖。每個對象都有,也僅有一個 Monitor。安全

下面經過一張圖片進行講解:多線程

1.一張圖片

圖片看不清,請點擊這裏 : 高清大圖ide

這裏寫圖片描述

2.圖片對應的代碼

import java.util.Date;

/**
 * 測試的object類
 *
 * @author:dufy
 * @version:1.0.0
 * @date 2017/9/29
 * @email 742981086@qq.com
 */
public class ObjectTest {


    public synchronized  void methodA(){
        try {
            System.out.println("This is methodA ...." + Thread.currentThread().getName() + ": " + new Date());
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public void methodB(){

        System.out.println("This is methodB ...." + Thread.currentThread().getName() + ": " + new Date());
    }

    public synchronized void methodC(){

        try {
            System.out.println("This is methodC ...." + Thread.currentThread().getName() + ": " + new Date());
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


}
package com.dufy.concurrentcode;

/**
 * 測試線程類
 *
 * @author:dufy
 * @version:1.0.0
 * @date 2017/9/29
 * @email 742981086@qq.com
 */
public class ThreadTest extends Thread{

    public static void main(String[] args) {
        ObjectTest ot = new ObjectTest();
        Thread1 t1 = new Thread1(ot,"thread1");
        Thread2 t2 = new Thread2(ot,"thread2");
        Thread3 t3 = new Thread3(ot,"thread3");
        Thread4 t4 = new Thread4(ot,"thread4");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }


    static class Thread1 extends Thread{
        private ObjectTest objectTest;

        public Thread1(ObjectTest objectTest,String name){
            setName(name);
            this.objectTest = objectTest;
        }
        @Override
        public void run() {
            super.run();
            objectTest.methodA();
        }
    }

    static class Thread2 extends Thread{
        private ObjectTest objectTest;

        public Thread2(ObjectTest objectTest,String name){
            setName(name);
            this.objectTest = objectTest;
        }
        @Override
        public void run() {
            super.run();
            objectTest.methodB();
        }
    }

    static class Thread3 extends Thread{
        private ObjectTest objectTest;

        public Thread3(ObjectTest objectTest,String name){
            setName(name);
            this.objectTest = objectTest;
        }
        @Override
        public void run() {
            super.run();
            objectTest.methodA();
        }
    }

    static class Thread4 extends Thread{
        private ObjectTest objectTest;

        public Thread4(ObjectTest objectTest,String name){
            setName(name);
            this.objectTest = objectTest;
        }
        @Override
        public void run() {
            super.run();
            objectTest.methodC();
        }
    }
}

運行結果:函數

This is methodB ....thread2: Fri Sep 29 23:21:17 CST 2017
This is methodA ....thread1: Fri Sep 29 23:21:17 CST 2017
This is methodC ....thread4: Fri Sep 29 23:21:18 CST 2017
This is methodA ....thread3: Fri Sep 29 23:21:21 CST 2017

 

注: 
一、運行的結果可能和上圖講的線程流程不一樣,沒有關係,只要理解對象鎖和synchronized的核心思想就好,線程的運行原本就是具備隨機性這個特色。 
二、此段代碼是同步方法,其實同步的代碼塊也是一個道理,同步代碼塊用synchronized(this)時候,當一個線程訪問object的一個synchronized(this)同步代碼塊的時候,其餘線程對object中全部其餘的synchronized(this)同步的代碼塊訪問都被阻塞 (阻塞的是同步代碼塊,線程依然能夠進入同步代碼塊的方法)。測試

3.總結

  1. 每一個對象都有一把鎖(對象監視器),關鍵字synchronized取得鎖都是對象鎖,而不是把一段代碼或方法(函數)當作鎖。
  2. 上圖所示,哪一個線程先執行帶有synchronized關鍵字的方法,哪一個線程就持有這個方法所屬對象的鑰匙。其餘線程只能處於等待狀態。
  3. 調用關鍵字synchronized聲明的方法,必定是排隊運行的。這纔是使用synchronized關鍵字的做用,排隊運行,若是有共享資源的話,那麼共享資源的讀取就是線程安全的。
  4. 若是一個線程持有 object的鑰匙,那麼其餘線程能夠訪問object對象沒有上鎖的方法,也就是非synchronized類型的方法。

4.Monitor和線程關係

首先看一下線程和 Monitor之間關係,以 及線程的狀態轉換圖。經過圖講解一下整個過程。this

這裏寫圖片描述

上圖分爲三塊:Entry Set(進入區) 、The Owner(擁有區)、Wait Set(等待區)。spa

  • Entry Set(進入區):表示線程經過synchronized要求獲取對象的鎖。若是對象未被鎖住,則迚入擁有者;不然則在進入區等待。一旦對象鎖被其餘線程釋放,當即參與競爭。.net

  • The Owner(擁有區):表示某一線程成功競爭到對象鎖。線程

  • Wait Set(等待區):表示線程經過對象的wait方法,釋放對象的鎖,並在等待區等待被喚醒。

從圖中能夠看出,一個 Monitor在某個時刻,只能被一個線程擁有,該線程就是 「Active Thread」,而其它線程都是 「Waiting Thread」,分別在兩個隊列 「 Entry Set」和 「Wait Set」裏面等候。

源碼下載地址:http://www.jinhusns.com/Products/Download

相關文章
相關標籤/搜索