java並發筆記二之證明 synchronized鎖 是否真實存在


警告⚠️:本文耗時很長,先做好心理准備
證明:偏向鎖、輕量級鎖、重量級鎖真實存在
【java並發筆記之java線程模型】鏈接: https://www.cnblogs.com/yuhangwang/p/11256476.html這篇文章可知:每當java線程創建的時候相對應的os pthread_create()也會創建一個線程,使用synchronized()就必然調用os pthread_mutex_lock() 函數
synchronized關鍵字鎖的狀態:無鎖、偏向鎖、輕量級鎖、重量級鎖
此篇文章由證明偏向鎖是否存在入手,眾所周知偏向鎖一定會保證線程安全 ,但是實際情況不一定有互斥,偏向鎖是synchronized鎖的對象沒有資源競爭的情況下,不會調用os pthread_mutex_lock() 函數; 但是第一次初始化使用鎖的時候確實會調用一次pthread_mutex_lock()進行偏向鎖
猜想: 偏向鎖一定真實存在
求證方法:
  1.修改Linux源碼中glibc庫中pthread_mutex_lock.c文件中的pthread_mutex_lock() 方法,增加輸出當前os id 語句;
  2.java代碼中使用synchronized關鍵字加鎖,打印出加鎖前線程id(此線程id會轉化為真實os 線程Id),1和2兩者相互比較;
  3.如果調用os pthread_mutex_lock() os-id 與 java thread-id 相同: 說明鎖真的存在, 並且只出現過一次相同為偏向鎖
開始求證:
環境搭建:(此處注意linux內核必須與gilbc庫相對應,否則編譯不成功
linux:centos 7  
Gilbc:Gilbc-2.19 官方gilbc鏈接http://mirror.hust.edu.cn/gnu/glibc/
避免踩坑,個人環境已經上傳百度網盤:請自行下載安裝 百度網盤地址:鏈接:https://pan.baidu.com/s/1LULbCoxm-ooPnZbGG3tdAQ 密碼:9jwu

檢查環境:
一、首先檢查自己的linux有沒有java環境:
    通過java、和javac兩個命令查看是否可用
    如果沒有則檢查一下yum當中有哪些JDK可以提供安裝命令:
yum search java | grep -i --color jdk

 如果沒有安裝,  以jdk8為例:

yum install -y java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64  

二、 在檢查inux環境要與gIibc版本是否相對應(不對應會導致編譯失敗)
三、檢查有沒有安裝gcc,用來編譯C程序,沒有就安裝gcc
yum -y install gcc

四、解壓glibc

tar -zxvf glibc-2.19.tar.gz

五、修改glibc的源碼

修改:pthread_mutex_lock()該方法,加入打印當前os threadId(也就是調用該方法時打印)
路徑:{your-dir}/glibc-2.19/nptl/pthread_mutex_lock.c---pthread_mutex_lock()
   pthread_mutex_lock.c文件下 pthread_mutex_lock() 函數下 第66行修改為:
     printf(stderr,”msg tid=%lu\n",pthread_self);
  (stderr:文件描述符,pthread_self:當前線程id)

修改完之后,以后所有調用pthread_mutex_lock()函數都會打印出自己的線程id
六、編譯剛才修改完的文件:
cd glibc-2.19

  編譯完成后要存放的文件位置:

mkdir out

   編譯(完成后覆蓋系統默認的文件,請提前備份默認文件,以防不測

cd out
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin

  執行:

make
//make 執行完畢之后再執行
make install

   測試 運行:

java

 只有調用了pthread_mutex_lock()會打印出自己的線程id:

  

表示此處修改linux源碼glibc庫下的pthread_mutex_lock()成功;
接下來就該驗證偏向鎖到底是不是真實存在的:
java代碼:
import java.lang.Thread;

public class ThreadTest {
    Object o= new Object();
    static {
        System.loadLibrary( "TestThreadNative" );
    }
    public static void main(String[] args) {
        //打印出主線程
        System.out.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        ThreadTest example4Start = new ThreadTest();
        example4Start.start();
    }
    public void start(){
        Thread thread = new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        sync();
                    } catch (InterruptedException e) {

                    }
                }
            }
        };

        Thread thread2 = new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        sync();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        thread.setName("t1");
        thread2.setName("t2");
        
        thread.start();
    }

    //.c 文件打印出java threaid 對應的os threadid
    public native void tid();

    public  void sync() throws InterruptedException {
        synchronized(o) {
            //java threadid 是jvm給的線程id 並不是真是的os 對應的線程id
            //System.out.println(Thread.currentThread().getId());

            //獲取java thread 對應的真實的os thread 打印出id
            tid();
        }
    }
}

獲取真實線程id(os 線程Id)的c文件:(對應上邊java代碼的 native void tid())

#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include "Example4Start.h"
JNIEXPORT void JNICALL Java_Example4Start_tid(JNIEnv *env, jobject c1){
    printf("current tid:%lu-----\n",pthread_self());
    usleep(700);
}

然后再走一遍生成.class、.h 、so 然后執行(此方法在 【java並發筆記之java線程模型】鏈接: https://www.cnblogs.com/yuhangwang/p/11256476.html中有相對應執行方法,請參考)
執行:
java ThreadTest
顯示: 

  

  

實錘:紅色的證明偏向鎖真實存在,綠色的證明synchronized 1.6之后偏向鎖做了優化(只調用了一次os 函數,后面沒有調用
同理輕量級鎖及重量級鎖也可以這樣證明出來 

 

 原創不易,轉載請標明出處,謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM