• 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
    ",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-----
    ",pthread_self());
        usleep(700);
    }
    

    然后再走一遍生成.class、.h 、so 然后执行(此方法在【java并发笔记之java线程模型】链接: https://www.cnblogs.com/yuhangwang/p/11256476.html中有相对应执行方法,请参考)
    执行:
    java ThreadTest
    显示: 

      

      

    实锤:红色的证明偏向锁真实存在,绿色的证明synchronized 1.6之后偏向锁做了优化(只调用了一次os 函数,后面没有调用
    同理轻量级锁及重量级锁也可以这样证明出来 

     原创不易,转载请标明出处,谢谢

  • 相关阅读:
    Ubuntu18.04下cuda和cudnn安装
    NVIDIA显卡驱动安装
    ultraiso(软碟通)制作u盘启动盘
    [转载]如何根据相机的参数知道摄像机的内参数矩阵
    C++ Primer : 第十三章 : 拷贝控制之拷贝、赋值与销毁
    用栈操作实现队列的操作
    C++ Primer : 第十二章 : 文本查询程序
    C++ Primer : 第十二章 : 动态内存之allocator类
    C++ Primer : 第十二章 : 动态内存之动态数组
    C++ Primer : 第十二章 : 动态内存之unique_ptr和weak_ptr
  • 原文地址:https://www.cnblogs.com/yuhangwang/p/11258599.html
Copyright © 2020-2023  润新知