警告⚠️:本文耗时很长,先做好心理准备
证明:偏向锁、轻量级锁、重量级锁真实存在

由【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 函数,后面没有调用)
同理轻量级锁及重量级锁也可以这样证明出来 

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

java并发笔记之证明 synchronized锁 是否真实存在的更多相关文章

  1. java并发笔记之四synchronized 锁的膨胀过程(锁的升级过程)深入剖析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. 本篇我们讲通过大量实例代码及hotspot源码分析偏向锁(批量重偏向.批量撤销).轻量级锁.重量级锁及锁的膨胀过程(也就是锁的升 ...

  2. Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...

  3. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

  4. java并发编程:深入了解synchronized

    简介 synchronized是Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.同时它还保证了共享变量的内存可见性. ...

  5. 【Java并发编程实战】-----synchronized

    在我们的实际应用当中可能经常会遇到这样一个场景:多个线程读或者.写相同的数据,访问相同的文件等等.对于这种情况如果我们不加以控制,是非常容易导致错误的.在java中,为了解决这个问题,引入临界区概念. ...

  6. Java 并发编程——volatile与synchronized

    一.Java并发基础 多线程的优点 资源利用率更好 程序设计在某些情况下更简单 程序响应更快 这一点可能对于做客户端开发的更加清楚,一般的UI操作都需要开启一个子线程去完成某个任务,否者会容易导致客户 ...

  7. Java并发(4)- synchronized与CAS

    引言 上一篇文章中我们说过,volatile通过lock指令保证了可见性.有序性以及"部分"原子性.但在大部分并发问题中,都需要保证操作的原子性,volatile并不具有该功能,这 ...

  8. Java并发笔记(二)

    1. 活跃性危险 死锁(最常见) 饥饿 当线程由于无法访问它所需的资源而不能继续执行时,就发生了饥饿.引发饥饿最常见资源就是CPU时钟周期. 活锁 活锁指的是任务或者执行者没有被阻塞,由于某些条件没有 ...

  9. 【Java并发编程实战】—–synchronized

    在我们的实际应用其中可能常常会遇到这样一个场景:多个线程读或者.写相同的数据,訪问相同的文件等等.对于这样的情况假设我们不加以控制,是非常easy导致错误的. 在java中,为了解决问题,引入临界区概 ...

随机推荐

  1. lodop+art-template实现web端漂亮的小票样式打印

    一. 现状 由于之前采用Lodop打印控件(商业版付费,可以使用免费版 但是会有水印)去打印小票,是一行一行的打印,但是不满足UI给到复杂布局的小票样式,所以得重新考虑如何来实现. 二. 介绍 art ...

  2. C++程序设计2(侯捷video all)

    一.转换函数Conversion function(video2) 一个类型的对象,使用转换函数可以转换为另一种类型的对象. 例如一个分数,理应该可以转换为一个double数,我们用以下转换函数来实现 ...

  3. 【Netty整理02-详细使用】Netty入门

    重新整理版:https://blog.csdn.net/the_fool_/article/details/83002152 参考资料: 官方文档:http://netty.io/wiki/user- ...

  4. kubernetes实战篇之helm安装

    系列目录 Helm是kubernetes的应用包管理工具,是CNCF孵化器下的一个项目,主要用来管理 Charts.类似于 Ubuntu 中的 APT 或 CentOS 中的 YUM.它提供了一种简单 ...

  5. 消息驱动式微服务:Spring Cloud Stream & RabbitMQ

    1. 概述 在本文中,我们将向您介绍Spring Cloud Stream,这是一个用于构建消息驱动的微服务应用程序的框架,这些应用程序由一个常见的消息传递代理(如RabbitMQ.Apache Ka ...

  6. LeetCode刷题------------------------------LeetCode使用介绍

    临近毕业了,对技术有种热爱的我也快步入码农行业了,以前虽然在学校的ACM学习过一些算法,什么大数的阶乘,dp,背包等,但是现在早就忘在脑袋后了,哈哈,原谅我是一枚菜鸡,为了锻炼编程能力还是去刷刷Lee ...

  7. 深入理解Java内存模型JMM与volatile关键字

    深入理解Java内存模型JMM与volatile关键字 多核并发缓存架构 Java内存模型 Java线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程内存模型是标准化的,屏蔽 ...

  8. HDU 1724:Ellipse(自适应辛普森积分)

    题目链接 题意 给出一个椭圆,问一个[l, r] 区间(蓝色区域)的面积是多少. 思路 自适应辛普森积分 具体一些分析如上. 很方便,套上公式就可以用了. 注意 eps 的取值影响了跑的时间,因为决定 ...

  9. 花5分钟时间来了解一下高性能网关Kong会有意外收获

    前言 前几天开源发布了 Kong.Net 项目,收到了大量园友的反馈,开源当天就突破了 100 个star ,可喜可贺,但是从侧面也说明,我们 .NetCore 阵营真的非常需要拥抱开源,应该敞开心扉 ...

  10. php的开始之路

    三大核心:封装,继承,多态 三大核心无处不在,不管是php传统的面向过程化编程,还是后来加入的oop面向对象编程,都一直贯穿整个php的发展进步史. 面向对象,面向接口五大原则:单一职责,封闭-开放, ...