深拷贝和浅拷贝
深拷贝和浅拷贝
深拷贝和浅拷贝是用来描述对象或者对象数组这种引用数据类型的复制场景的。
浅拷贝就是只复制某个对象的指针,而不复制对象本身。
这种复制方式意味着两个引用指针指向被复制对象的同一块内存地址。
深拷贝会完全创建一个一模一样的新对象,新对象和老对象不共享内存,也就意味着对新对象的修改不会影响老对象的值。
在Java里面,无论是深拷贝还是浅拷贝,都需要通过实现Cloneable接口,并实现clone()方法。
然后我们可以在clone()方法里面实现浅拷贝或者深拷贝的逻辑。
实现深拷贝的方法有很多,比如
通过序列化的方式实现,也就是把一个对象先序列化一遍,然后再反序列化回来,就会得到一个完整的新对象。
在clone()方法里面重写克隆逻辑,也就是对克隆对象内部的引用变量再进行一次克隆。
伪共享的概念以及如何避免
首先,计算机工程师为了提高CPU的利用率,平衡CPU和内存之间的速度差异,在CPU里面设计了三级缓存。
CPU在向内存发起IO操作的时候,一次性会读取64个字节的数据作为一个缓存行,缓存到CPU的高速缓存里面。
在Java中一个long类型是8个字节,意味着一个缓存行可以存储8个long类型的变量。
这个设计是基于空间局部性原理来实现的,也就是说,如果一个存储器的位置被引用,那么将来它附近的位置也会被引用。
所以缓存行的设计对于CPU来说,可以有效的减少和内存的交互次数,从而避免了CPU的IO等待,以提升CPU的利用率。
正是因为这种缓存行的设计,导致如果多个线程修改同一个缓存行里面的多个独立变量的时候,基于缓存一致性协议,就会无意中影响了彼此的性能,这就是伪共享的问题。
像这样一种情况,CPU0上运行的线程想要更新变量X、CPU1上的线程想要更新变量Y,而X/Y/Z都在同一个缓存行里面。
每个线程都需要去竞争缓存行的所有权对变量做更新,基于缓存一致性协议。
一旦运行在某个CPU上的线程获得了所有权并执行了修改,就会导致其他CPU中的缓存行失效。
这就是伪共享问题的原理。
因为伪共享会问题导致缓存锁的竞争,所以在并发场景中的程序执行效率一定会收到较大的影响。
这个问题的解决办法有两个:
使用对齐填充,因为一个缓存行大小是64个字节,如果读取的目标数据小于64个字节,可以增加一些无意义的成员变量来填充。
在Java8里面,提供了@Contented注解,它也是通过缓存行填充来解决伪共享问题的,被@Contented注解声明的类或者字段,会被加载到独立的缓存行上。
在Netty里面,有大量用到对齐填充的方式来避免伪共享问题。
- 点赞
- 收藏
- 关注作者
评论(0)