本文共 2688 字,大约阅读时间需要 8 分钟。
在学习Java Web开发过程中,尤其是在接触Java线程开发时,常常会遇到一个令人困惑的问题:当多个线程调用同一个方法时,变量会如何变化?这个问题引出了线程安全的概念,包括原子性、有序性和可见性。但在实际开发中,如何选择合适的线程安全类型仍然是一个值得探讨的话题。
我们来看一段代码:
public class Main { private static final int NUM = 1 << 20; // 定义一个大数 1M private static ExecutorService threadPool = Executors.newCachedThreadPool(); private static int normalInt = NUM; private static AtomicInteger atomicInt = new AtomicInteger(NUM); private static ThreadLocallocalInt = ThreadLocal.withInitial(() -> NUM); public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(NUM); long begin = System.currentTimeMillis(); // 计时开始 for (int i = 0; i < NUM; i++) { threadPool.execute(() -> { // 分别用对应方法迭减 normalInt--; atomicInt.getAndAdd(-1); localInt.set(localInt.get() - 1); // latch计数 latch.countDown(); }); } long time = System.currentTimeMillis() - begin; // 计时结束 latch.await(); // 等待任务完成切回主线程 System.out.println("Origin: 2^20 = " + NUM + " normal: " + normalInt + " atomic: " + atomicInt.get() + " local: " + localInt.get()); System.out.println("time: " + time / 1000D + "s"); threadPool.shutdown(); }}
代码背景:我们创建了1M个相同的任务,利用线程池进行多线程执行。每个任务都对三个成员变量分别进行递减操作。
预期结果:最后期望所有变量都变为0。
实际输出:
Origin: 2^20 = 1048576 normal: 3121 atomic: 0 local: 1048576time: 4.973s
线程安全问题的一个经典案例是基础类型变量的线程不安全。让我们分析一下原因。
基础类型的迭减操作不是原子操作:迭减的本质是通过创建临时变量来存储“x-1”的结果,然后将这个值赋给x。这意味着迭减操作可以被分解为读取和写入操作。
线程冲突:假设有两个线程同时对同一个变量执行迭减操作:
最终,x的值只会减少一次。这就是为什么我们会看到非零的输出。
测试结果显示,基础类型的迭减操作在多线程环境下会出现3121次插入现象,导致最终变量未能成功减到0。这表明基础类型在并发环境下是不安全的。
ThreadLocal类型在我们的测试中没有显示出任何变化。这与ThreadLocal的本质密切相关。
ThreadLocal内部维护了一个HashMap,每个访问ThreadLocal变量的线程都会分配到一个独立的拷贝。因此,主线程最后输出的值实际上没有被任何工作线程修改过,仍然保持原值。
ThreadLocal的优势在于它可以统一管理共享类任务中的变量,避免了传统的锁同步编程的复杂性。
原子类型提供了更高的线程安全性。例如,AtomicInteger的实现源代码如下:
private static final Unsafe U = Unsafe.getUnsafe();private volatile int value;public final int getAndAdd(int delta) { return U.getAndAddInt(this, 0, delta);}
原子类型的优势在于其内部使用乐观锁机制,性能通常优于传统的锁同步编程。从敏捷开发的角度来看,原子类型在并发环境下的表现更为出色。
通过以上分析,我们可以得出以下结论:
在实际开发中,选择合适的线程安全类型取决于具体需求。无论是基础类型+锁,还是原子类型,都有其适用的场景。
转载地址:http://jyiwz.baihongyu.com/