专业购物网站定制商业网站建设目标
2026/2/13 14:44:19 网站建设 项目流程
专业购物网站定制,商业网站建设目标,手机网站优化技巧,安卓排名优化当 ThreadLocal 不加 static 修饰时#xff0c;会发生 每个实例都有自己的 ThreadLocal 对象#xff0c;这会导致严重的线程数据混乱问题。 本篇博文我通过如下代码来演示这个问题#xff1a; 修改后的示例#xff1a;不加 static 的 ThreadLocal import java.util.ArrayLi…当ThreadLocal不加static修饰时会发生每个实例都有自己的 ThreadLocal 对象这会导致严重的线程数据混乱问题。本篇博文我通过如下代码来演示这个问题修改后的示例不加static的 ThreadLocalimportjava.util.ArrayList;importjava.util.List;classSharedObject{privateintcounter0;publicvoidincrement(){counter;}publicintgetCounter(){returncounter;}}classThreadLocalNonStaticExample{// 注意这里去掉了 static 修饰符privateThreadLocalSharedObjectthreadLocalThreadLocal.withInitial(()-newSharedObject());publicvoidupdateCounter(){SharedObjectsharedthreadLocal.get();shared.increment();System.out.println(Thread.currentThread().getName() - Counter: shared.getCounter() - ThreadLocal hash: System.identityHashCode(threadLocal));}publicstaticvoidmain(String[]args)throwsInterruptedException{// 创建两个不同的实例ThreadLocalNonStaticExampleexample1newThreadLocalNonStaticExample();ThreadLocalNonStaticExampleexample2newThreadLocalNonStaticExample();System.out.println(两个实例的 ThreadLocal 对象是否相同: (example1.threadLocalexample2.threadLocal));System.out.println(example1.threadLocal hash: System.identityHashCode(example1.threadLocal));System.out.println(example2.threadLocal hash: System.identityHashCode(example2.threadLocal));Threadthread1newThread(()-{System.out.println(\n 线程1执行 );// 同一个线程但访问不同实例的 ThreadLocalexample1.updateCounter();// 输出 1example1.updateCounter();// 输出 2example2.updateCounter();// 输出 1 - 因为是不同的 ThreadLocal},Thread-1);Threadthread2newThread(()-{System.out.println(\n 线程2执行 );example1.updateCounter();// 输出 1 - 新线程新的 ThreadLocalMapexample2.updateCounter();// 输出 1},Thread-2);thread1.start();thread1.join();thread2.start();thread2.join();}}更复杂的场景内存泄漏风险classMemoryLeakExample{// 非 static 的 ThreadLocalprivateThreadLocalListStringdataThreadLocalThreadLocal.withInitial(()-newArrayList());publicvoidaddData(Stringdata){dataThreadLocal.get().add(data);}publicvoidprintData(){System.out.println(Thread.currentThread().getName() 数据: dataThreadLocal.get());}publicstaticvoidmain(String[]args)throwsInterruptedException{// 模拟大量创建实例ListMemoryLeakExampleexamplesnewArrayList();ThreadthreadnewThread(()-{for(inti0;i1000;i){MemoryLeakExampleexamplenewMemoryLeakExample();examples.add(example);example.addData(data-i);if(i%1000){System.out.println(创建了 i 个实例);System.out.println(当前线程 ThreadLocalMap 中的 Entry 数量会不断增加...);}}// 每个实例都有自己的 ThreadLocal 对象作为 key// 在 ThreadLocalMap 中会有大量 Entry});thread.start();thread.join();System.out.println(\n总计创建了 examples.size() 个实例);System.out.println(这意味着在当前线程的 ThreadLocalMap 中有 examples.size() 个不同的 ThreadLocal key);}}在线程池中的灾难性后果importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;classThreadPoolProblem{// 非 static ThreadLocalprivateThreadLocalIntegercounterThreadLocalThreadLocal.withInitial(()-0);publicvoidincrement(){IntegercountcounterThreadLocal.get();counterThreadLocal.set(count1);}publicintgetCount(){returncounterThreadLocal.get();}publicstaticvoidmain(String[]args)throwsInterruptedException{ExecutorServiceexecutorExecutors.newFixedThreadPool(2);// 任务每个任务创建一个新实例for(inti0;i10;i){inttaskIdi;executor.submit(()-{ThreadPoolProbleminstancenewThreadPoolProblem();instance.increment();instance.increment();System.out.println(任务 taskId线程: Thread.currentThread().getName()计数: instance.getCount()ThreadLocal hash: System.identityHashCode(instance.counterThreadLocal));// 问题线程池线程复用但每次任务都创建新的 ThreadLocal// 导致 ThreadLocalMap 中积累大量 stale entries});}executor.shutdown();}}不加static的问题总结线程隔离失效每个实例有自己的ThreadLocal对象同一个线程访问不同实例时会使用不同的ThreadLocalkey无法实现真正意义上的线程级数据共享内存泄漏// 每次创建新实例ThreadLocalNonStaticExampleobjnewThreadLocalNonStaticExample();// 都会创建新的 ThreadLocal 对象// ThreadLocalMap 中会积累ThreadLocal(key) - value// 线程不结束这些 entry 就一直存在ThreadLocalMap 膨胀每个线程的ThreadLocalMap中会有大量 key每个实例一个即使实例被回收ThreadLocal 是弱引用但 value 可能还在数据不一致// 线程1example1.updateCounter();// 使用 example1.threadLocalexample2.updateCounter();// 使用 example2.threadLocal不同的存储位置// 它们不是同一个 ThreadLocal所以不共享数据性能问题每次都要创建新的ThreadLocal对象ThreadLocalMap查找效率降低hash 冲突增加正确 vs 错误对比// ✅ 正确static ThreadLocalpublicclassCorrectExample{privatestaticThreadLocalContextcontextThreadLocal.withInitial(Context::new);// 所有实例共享同一个 ThreadLocal 对象// 线程数据真正隔离}// ❌ 错误非 static ThreadLocalpublicclassWrongExample{privateThreadLocalContextcontextThreadLocal.withInitial(Context::new);// 每个实例都有自己的 ThreadLocal// 线程数据混乱}结论ThreadLocal必须使用static修饰确保所有实例共享同一个ThreadLocal对象作为 key这样才能正确实现线程级别的数据隔离。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询