博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从classloader的变更说起
阅读量:7237 次
发布时间:2019-06-29

本文共 2233 字,大约阅读时间需要 7 分钟。

  hot3.png

classloader从1.6到1.7整体分成了两个版本。重点区别就是并行类加载。

1.6版本

protected synchronized Class loadClass(String name, boolean resolve)        throws ClassNotFoundException    {		……        return c;    }

1.6版本加了一个方法锁。

1.7版本

private final ConcurrentHashMap parallelLockMap;      protected Class loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {	        ……            return c;        }    }    protected Object getClassLoadingLock(String className) {        Object lock = this;        if (parallelLockMap != null) {            Object newLock = new Object();            lock = parallelLockMap.putIfAbsent(className, newLock);            if (lock == null) {                lock = newLock;            }        }        return lock;    }

1.7之后就是用了两种模式getClassLoadingLock方法中,我们可以看出有两种模式,一种是parallelLockMap为空,锁的对象是classloader本身,另外一种是parallelLockMap不为null。这里会根据classname去获取锁,如果有返回的object不为null。说明已经有class使用过了,如果为null,就把新建的object当做锁,达到了一个classname一个锁的效果。

classloader加锁的原因

有很多classloader的例子直接复写了loadClass但是没有加锁,只有读取文件加载的过程,这种classloader都是特定场合使用的。并不具备通用性。众所周知的一个规则,一个classloader不能加载相同类的字节码,第二次加载就会在defineclass的时候报错。

场景1
不同的线程可以是相同的classloader,两个线程的都是A classloader加载的,当里面的有个方法里都有B类时,两个线程都会触发A加载B类
场景2
双亲委托的情况,A loader是B loader的parent。A能加载到C类。B loader加载c的时候委托给A,A也在同时加载C。此时触发了两次A加载C。

锁分离的好处

锁分离加快了并发,这个是显而易见的。还有一个好处是减少了死锁。在编写javaagent的时候,只要在transform加点锁,特别容易和classloader还有类初始化时候的锁造成死锁。基本死锁的场景都在1.6。

锁分离的案例

jdk中锁分离的实现特别多

读写分离

双锁读写分离

LinkedBlockingQueue有两把锁takeLock和putLock。 由于队列的特性——FIFO。在写入的时候,竞争takeLock。读取的时候竞争putLock。以此达到同事读写的增加吞吐量的目的。
副本机制读写分离
副本机制读写分离的典型就是copyonwrite。 CopyOnWriteArrayList。只有一把lock。但是使用的是数组存储。用volatile修饰。写入的时候获取锁,先用一个新的数组把旧的数据拷贝过来,然后把要加入的数据放入新数组中。最后替换 volatile的引用。读取的时候就直接获取volatile的数组。 这样读取的时候只是那一刻的副本,一旦开始遍历,直到结束都不会有新的数据加入了。

写写分离

写写分离的场景是锁细化。classloader的改进算是写写分离的情况。典型的场景就是ConcurrentHashMap。ConcurrentHashMap的每个槽位一把锁,当没有hash冲突的时候,元素的写的过程是并行的。

集群锁分离

集群的锁分离的场景我们也用到的特别多。主要目的是提供并发。

  1. kafka 消费(读写分离)。kafka写log,达到一定限制就会开启新的文件,消费的时候,从旧的开始,就会从已经写好的开始读取。这种情况下,读文和写的文件是两个不同的文件。
  2. kafka topic分区。(写写分离)。kafka写入根据分区算法。分别写入不同的partition。类似的还有分库,分表。只要是水平扩展的基本都是写写分离的。
  3. 主从机制(副本机制读写分离)。数据库使用主备方案,并且备份库只提供读取操作。至于新入的数据的空缺,一般由redis等缓存弥补。

转载于:https://my.oschina.net/xpbob/blog/3000780

你可能感兴趣的文章
FineUI 将不再内置 ExtJS (严格遵守 ExtJS 的开源规则)
查看>>
javascript 中contentWindow和 frames和iframe之间通信
查看>>
取得正在运行的Activity
查看>>
因无力偿还网贷 内蒙古一对夫妻贩卖亲生龙凤胎
查看>>
张近东智慧零售大开发加码:2019年开店15000家
查看>>
西班牙一亚洲女子疑似被人从三楼推落 伤势严重
查看>>
学习Python编程语言-这28本有关Python书籍值得去了解
查看>>
刚刚,蚂蚁区块链喜提“世界互联网领先科技成果”
查看>>
华为资深架构师:Cloud Native架构一致性问题及解决方案
查看>>
AI还有什么不会的?机器人写稿技术应用
查看>>
iOS 中的 block 是如何持有对象的
查看>>
从业务变迁到研发犯难,微服务在Spring Cloud的实践之路
查看>>
Python 连接 MySQL 的几种姿势
查看>>
跨页面通信的各种姿势
查看>>
Java 开发者最容易犯的10个错误
查看>>
Web 探索之旅 | 第三部分第一课:服务器
查看>>
0110 - 给 iPhone 6 换了电池
查看>>
Android-Rxjava+Retrofit2.x 获取Http状态码、响应头(Headers)等数据
查看>>
swift版indexOfObject()
查看>>
第二十九章:基于SpringBoot平台使用Lombok来优雅的编码
查看>>