设为首页 加入收藏

TOP

Synchronized详解(二)
2023-07-25 21:35:26 】 浏览:47
Tags:Synchronized 详解
Thread thread2 = new Thread(instance2); thread1.start(); thread2.start(); while(thread1.isAlive()||thread2.isAlive()){ } System.out.println("finish"); } }

在这个案例中,存在两个SynchronizedClassClass对象,但是不能同时访问同步代码

4.类锁:static形式

static形式说的是static修饰synchronized修饰的方法,即static synchronized methodName,作用方法还是这个类的class对象

public class SynchronizedClassStatic implements Runnable{
    private static SynchronizedClassStatic instance1=new SynchronizedClassStatic();
    private static SynchronizedClassStatic instance2=new SynchronizedClassStatic();
    public static synchronized void method(){
        System.out.println("我是类锁的形式之一:加static修饰。我叫"+Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"运行结束");
    }
    public void  method2(){
        System.out.println("我是非静态方法,我叫"+Thread.currentThread().getName());
    }
    @Override
    public void run() {
        method();
        method2();
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(instance1);
        Thread thread2 = new Thread(instance2);
        thread1.start();
        thread2.start();
        while(thread1.isAlive()||thread2.isAlive()){
        }
        System.out.println("finish");
    }
}

二、synchronized的原理

让我们从字节码来看看synchronized的神秘面纱, 我们反编译synchronized修饰object的java文件

public class Decompilation {
    private Object object=new Object();

    public void insert(Thread thread){
        synchronized (object){

        }
    }
}

反编译指令为 javap -c -v YourName.java

所以就是这个小小的Monitor Enter和monitorexit指令完成了同步操作,关于Monitor Enter和monitorexit的定义可以查看jvm文档 中的注释

先看看 Monitor Enter,注意紫色标注


再看看Monitor Exit

这里就解释清楚为什么synchronized上的锁是可重入的,对于更深入的理解

重点还是提到的Monitor这个概念

我们再反编译synchronize修饰的同步方法,其结果是

与之前不一样,这里是在方法的访问标识上添加了ACC_SYNCHRONIZED,它在jvm文档中是这么解释

大致意思就是当调用设置了 ACC_SYNCHRONIZED 的方法时,执行线程进入监视器(monitor),然后执行这个方法,方法执行完毕后退出监视器。在执行线程拥有监视器期间,没有其他线程可以进入这个方法.

同样,这里涉及了Monitor

2.1 深入Monitor

虽然HotSpot的JDK代码没有开元,但好在还有OpenJDK,大家有时间可以看看ObjectMonitor.hpp和ObjectMonitor.cpp,如果c语言功力不好的同学,看看注释,大致知道每个变量啥意思即可。

image-20230327165124910

主要是_owner,_recursions,_entryList,_waitSet,此外还有header这个对象头将对象和Monitor联系起来。

_owner顾名思义就是锁的拥有者,recursions就是锁的进入次数,初始为0,而_entryList是存放Blocked状态的线程的,waitSet是存放Waiting状态的线程。

在HotSpot中,一个对象是在Heap中的存储布局有三个部分:对象头(Header),实例数据(Instance Data)以及对齐填充部分,而对象头一般由两个部分组成:MarkWord和类型指针,如果是数组对象,那么还有数组长度信息。

而MarkWord就是连接Monitor和对象的关键东西。它存储了对象运行时的一些数据,比如HashCode,GC年龄,锁的状态,线程所持有的锁等。

image-20230327210942749

总之,monitor才是synchronized并发的关键,monitor是底层用cpp实现的一个对象,实现了锁的状态转换,获取释放等方法,通过markword与java对象联系一起,而markword是嵌入在java头部的。

三、synchornized的各种锁以及优化

3.1 锁的升级

从jdk1.6开始,synchronized锁有四种状态,级别由低到高是

无锁,偏向锁,轻量锁,重量锁

锁的升级过程是一个很麻烦的事情,本质就是如果发生了锁的竞争就升级锁,直到升级到重量锁为止,期间使用到了CAS和自旋来避免线程直接进入阻塞状态。有兴趣的同学可以看看《阿里巴巴java性能调优实战》这本书。

3.2 JIT 实现锁消除和锁粗化

锁消除的概念比较容易理解,就是如果编译器认定一个锁只会被单个线程访问,那么这个锁就可以被消除。而锁粗化,简单的说就是JIT动态编译时发现相邻的同步块使用的是同一个锁实例,那么就合并他们,避免频繁加锁释放锁。

3.3 减少锁的粒度

这是我们平时编程的时候,我们可以控制的,有的同学(比如我)图省事往往可以加对象锁的,直接加类锁,这样就是不地道的。

《阿里巴巴java性能调优实战》举例说明减少锁的粒度的好处,比如被抛弃的HashTable和新宠ConcurrentHashMap的转换,就是使用了减少锁的粒度方法。

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇MySQL面经 下一篇复杂「场景」数据导入导出

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目