预分配TLAB可减少CAS竞争,因每个线程独享本地内存区域,分配时仅移动本地指针无需同步;仅当TLAB耗尽需申请新空间时才触发全局CAS操作。

Java中多个线程并发在堆中申请空间时,并不使用CAS加锁来保证安全——因为堆内存分配本身不是靠CAS实现的,也不是靠“加锁”完成的。
堆内存分配由JVM直接管理,不走CAS逻辑
JVM在为对象分配堆内存时(如执行 new Object()),主要依赖以下机制:
- TLAB(Thread Local Allocation Buffer):每个线程独享一小块堆内存区域,分配直接在本地缓冲区进行,无需同步;这是主流JVM(HotSpot)默认开启的优化,90%以上的对象都在TLAB中快速分配。
- 指针碰撞(Bump-the-Pointer):在连续空闲内存(如使用Serial或Parallel GC的年轻代 Eden 区)中,JVM只需原子地移动一个全局指针(如Eden top指针),这个操作确实可能用到CAS——但它是JVM内部对指针的原子更新,不是开发者能调用或配置的CAS加锁。
- 空闲列表(Free List):当内存不连续时(如CMS、G1的老年代),JVM维护空闲块链表,分配需从链表摘节点,此时可能用CAS更新链表头指针,仍属JVM底层实现,与业务代码无关。
CAS在Java并发中不用于“堆分配”,而是用于原子状态控制
CAS的典型用途是保障共享变量的线程安全修改,例如:
-
AtomicInteger.incrementAndGet():底层用Unsafe.compareAndSet更新int值; -
ConcurrentHashMap扩容时对table数组的volatile引用+CAS更新; -
AbstractQueuedSynchronizer(AQS)中state字段的CAS变更,支撑ReentrantLock等锁的实现。
这些场景操作的是已分配好的对象字段或状态变量,而非分配新对象本身。
立即学习“Java免费学习笔记(深入)”;
为什么不用CAS“锁住堆分配”?
堆分配若真靠CAS串行化,会严重拖慢性能——每new一个对象都要CAS竞争,违背TLAB设计初衷。实际中:
- TLAB分配失败时,才触发共享Eden区的同步分配,此时JVM用轻量级同步(如CAS更新top指针或自旋锁),但这是JVM内建行为,不可见、不可干预;
- 开发者无法、也不应手动对堆分配加CAS或任何锁——这既无API支持,也违反JVM内存模型抽象。
你真正需要关注的安全点在哪?
如果你担心多线程下对象创建后的使用安全,重点不在“分配过程”,而在:
- 对象初始化是否完成(注意
final字段的正确发布); - 对象被多个线程共享后,其内部可变状态是否受保护(如用synchronized、ReentrantLock或原子类);
- 避免构造器逃逸(this引用在构造完成前被发布)导致未完全初始化的对象被其他线程访问。
堆分配本身是线程安全的,JVM已为你兜底。你该操心的是对象“出生后”的行为,而不是它“出生那一刻”的锁。


















