Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 线程

  • 共享模型

  • 非共享模型

    • ThreadLocal
      • ThreadLocal是什么?
      • 案例
      • 源码
      • 内存泄漏
    • Actor
  • 并行

  • 多线程设计模式

  • JUC
  • 非共享模型
Nreal
2023-11-01
目录

ThreadLocal

# ThreadLocal是什么?

提供了一种线程本地变量的机制,每个线程都有自己独立副本,互补干扰;意味着每个线程可以独立操作自己的变量副本,不会影响其它线程副本;

# 案例

private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
    Thread thread1 = new Thread(() -> {
        threadLocal.set("value1");
        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
        threadLocal.remove(); // 可以手动调用 remove() 方法来清除当前线程的变量副本
    });
    Thread thread2 = new Thread(() -> {
        threadLocal.set("value2");
        System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
        threadLocal.remove();
    });
    thread1.start();
    thread2.start();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

访问threadLocal这个变量的每个线程都有这个变量的副本,可以使用 get()和 set() 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题;

# 源码

Thread

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
}
1
2
3

ThreadLocal

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

1
2
3
4
5
6
7
8
9
10
11
12

ThreadLocal是ThreadLocalMap的封装,每个Thread都有一个ThreadLocalMap,可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对

ThreadLocalMap

static class ThreadLocalMap {

    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11

# 内存泄漏

ThreadLocalMap的key为弱引用,如果ThreadLocal没有被外部强引用,在垃圾回收时,key会被清理掉,而val不会被清理,所以产生内存泄露,使用完ThreadLocal后,手动调用remove方法。

  • 为什么key为弱引用?

    便于下次垃圾回收清理掉,假如用户A执行方法时产生一份ThreadLocalA,很长时间都用不到,占用系统资源

  • 为什么val为强引用?

    ThreadLocal在运行期间都是强引用,如果val是弱引用,val就是只被Entry这个弱引用引用,发生gc时,threadLocal不会被回收,而val会被回收,导致ThreadLocal获得的val值为null,丧失了存储本地变量的意义

动态线程池
Actor

← 动态线程池 Actor→

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式