首先,我们先来梳理下,JVM是如何给对象分配内存的:
如果JIT的逃逸分析后该对象没有逃逸,那么可能优化到栈上分配。
如果被判断为大对象,则直接分配到直接进入老年代,譬如很长的字符串和数组,避免为大对象分配内存时由于分配担保机制带来的复制而降低效率 。可以设置
-XX:PretenureSizeThreshold
,令大于该尺寸的对象直接进入老年代。
简而言之,如下图所示:
所以,我们到这里就很清楚了,当给对象分配内存的时候,有可能在栈上分配,这自然不存在线程安全问题。除此之外,如果在堆上分配,则可能会启动TLAB机制,使得堆内存给线程单独划分空间,避免了线程安全的问题。
同时,当不启动TLAB机制的时候,如果一个空间被多个线程同时分配对象,JVM会采用CAS+失败重试的方式来避免线程问题。(具体的CAS机制和其利弊可以移步到JAVA并发专栏)
简而言之,是采用乐观锁的方式,只有假定该堆没有被其他线程操作的时候,当前线程才会在堆上分配对象,如果被其他线程操作,就获取当前堆中的最新标识,然后重试
评论区