学校网站建设背景,做竞价网站用什么系统好,瀑布流模板中加入广告 wordpress,海外代发货平台问题描述
我们在使用threadLocal的时#xff0c;使用ThreadLocal.withInitial去初始化而不是使用new ThradLocal去初始化#xff0c;这是为什么呢#xff1f;
问题例子
比如说#xff0c;假设我们想要在每个线程中维护一个独立的计数器
import java.util.concurrent.at…问题描述
我们在使用threadLocal的时使用ThreadLocal.withInitial去初始化而不是使用new ThradLocal去初始化这是为什么呢
问题例子
比如说假设我们想要在每个线程中维护一个独立的计数器
import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocalExample {import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocalExample {private static final ThreadLocalAtomicInteger counterThreadLocal new ThreadLocal();public static void main(String[] args) {// 创建多个线程for (int i 0; i 5; i) {new Thread(() - {// 获取 ThreadLocal 变量并递增计数器int count counterThreadLocal.get().getAndIncrement();System.out.println(线程 Thread.currentThread().getId() 计数: count);}).start();}}
}这个程序实际会报错 首先要说明一下这个代码并不是实现多线程的累加
import java.util.concurrent.atomic.AtomicInteger;public class MultiThreadedIncrement {private static final AtomicInteger counter new AtomicInteger(0);public static void main(String[] args) {// 创建多个线程进行累加for (int i 0; i 5; i) {new Thread(() - {// 在多线程环境下使用AtomicInteger进行累加for (int j 0; j 10000; j) {counter.incrementAndGet();}}).start();}// 等待所有线程执行完毕try {Thread.sleep(1000); // 这里仅为示例实际使用中可能需要更精确的等待方式} catch (InterruptedException e) {e.printStackTrace();}// 输出最终累加结果System.out.println(累加结果: counter.get());}
}多线程的累加是这样的一定要注意。而本案例是想实现每个线程独立维护一个计数器互不干涉。 或者我们这样来写大家可以看的更清楚 import java.util.concurrent.atomic.AtomicInteger;
public class ThreadLocalIncrement {private static final ThreadLocalAtomicInteger threadLocalCounter ThreadLocal.withInitial(AtomicInteger::new);public static void main(String[] args) {// 创建多个线程进行递增for (int i 0; i 5; i) {new Thread(() - {// 获取当前线程的计数器AtomicInteger counter threadLocalCounter.get();// 在每个线程中递增计数器for (int j 0; j 10000; j) {counter.incrementAndGet();System.out.println(线程 Thread.currentThread().getId() 计数: counter.get());}}).start();}}
}我们知道thread底层是基于treadmap实现的 ThreadLocal 使用了一个名为 ThreadLocalMap 的内部类它是 Thread 类的一个字段。 每个线程都有自己的 ThreadLocalMap 实例它是一个自定义的散列表结构。在 ThreadLocalMap 中ThreadLocal 实例作为键与之关联的值则存储在相应的槽位中。每个 ThreadLocal 实例在自己所属线程的 ThreadLocalMap 中有一个条目。 当你调用 ThreadLocal 的 get 方法时实际上是在当前线程的 ThreadLocalMap 中查找与该 ThreadLocal 实例关联的值。而调用 set 方法则是在当前线程的 ThreadLocalMap 中设置对应的关联值。 这种设计的好处在于每个线程都有自己独立的存储空间不需要锁定或同步从而提高了并发性能。 总体来说虽然底层并不直接使用标准的 Map 实现但可以将 ThreadLocalMap 看作是一个简化版的散列表 解决
我们可以简单理解为这就是一个mapkey就是每个线程的threadLacle实例value就是要存的值 实际上每个线程在开始执行时实例化threadLocal并没有初始化值而是一开始threalLocal的值就是null,所以在执行get方法的时候实际上取得是一个null值。所以null.getAndIncrement()自然会报错 我们可以这样修改
import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocalExample {private static final ThreadLocalAtomicInteger counterThreadLocal new ThreadLocal();public static void main(String[] args) {// 创建多个线程for (int i 0; i 5; i) {new Thread(() - {// 检查 ThreadLocal 变量是否为 null如果为 null则设置初始值if (counterThreadLocal.get() null) {counterThreadLocal.set(new AtomicInteger());}// 获取 ThreadLocal 变量并递增计数器int count counterThreadLocal.get().getAndIncrement();System.out.println(线程 Thread.currentThread().getId() 计数: count);}).start();}}
} 或者我们也可以使用ThreadLocal.withInitial来避免这个问题
import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocalExample {private static final ThreadLocalAtomicInteger counterThreadLocal ThreadLocal.withInitial(AtomicInteger::new);public static void main(String[] args) {// 创建多个线程for (int i 0; i 5; i) {new Thread(() - {// 获取 ThreadLocal 变量并递增计数器int count counterThreadLocal.get().getAndIncrement();System.out.println(线程 Thread.currentThread().getId() 计数: count);}).start();}}
}总结
在上述例子中counterThreadLocal 是一个 ThreadLocal 变量初始值是一个 AtomicInteger 计数器。每个线程第一次访问 counterThreadLocal 时都会调用 AtomicInteger::new 获取一个新的 AtomicInteger 实例作为初始值。每个线程都有自己独立的计数器互不干扰。
如果我们使用 new ThreadLocal(); 创建 ThreadLocal 实例它的初始值将为 null。这样每个线程第一次访问 ThreadLocal 变量时都会得到 null。这可能需要额外的逻辑来处理初始值增加了出错的可能性。所以使用 ThreadLocal.withInitial 提供了一种更清晰和线程安全的方式来初始化 ThreadLocal 变量。