threadlocal的缺点,threadlocal应用场景

首页 > 技术 > 作者:YD1662023-04-15 23:39:40

非线程安全的执行流程是这样的:

threadlocal的缺点,threadlocal应用场景(5)

b) 解决线程安全问题:加锁

当出现线程安全问题时,我们想到的第一解决方案就是加锁,具体的实现代码如下:

import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class App { // 时间格式化对象 private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss"); public static void main(String[] args) throws InterruptedException { // 创建线程池执行任务 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000)); for (int i = 0; i < 1000; i ) { int finalI = i; // 执行任务 threadPool.execute(new Runnable() { @Override public void run() { // 得到时间对象 Date date = new Date(finalI * 1000); // 执行时间格式化 formatAndPrint(date); } }); } // 线程池执行完任务之后关闭 threadPool.shutdown(); } /** * 格式化并打印时间 * @param date 时间对象 */ private static void formatAndPrint(Date date) { // 执行格式化 String result = null; // 加锁 synchronized (App.class) { result = simpleDateFormat.format(date); } // 打印最终结果 System.out.println("时间:" result); } }

以上程序的执行结果为:

threadlocal的缺点,threadlocal应用场景(6)

从上述结果可以看出,使用了 synchronized 加锁之后程序就可以正常的执行了。

加锁的缺点

加锁的方式虽然可以解决线程安全的问题,但同时也带来了新的问题,当程序加锁之后,所有的线程必须排队执行某些业务才行,这样无形中就降低了程序的运行效率了

有没有既能解决线程安全问题,又能提高程序的执行速度的解决方案呢?

答案是:有的,这个时候 ThreadLocal 就要上场了。

c) 解决线程安全问题:ThreadLocal1.ThreadLocal 介绍

ThreadLocal 从字面的意思来理解是线程本地变量的意思,也就是说它是线程中的私有变量,每个线程只能使用自己的变量。

以上面线程池格式化时间为例,当线程池中有 10 个线程时,SimpleDateFormat 会存入 ThreadLocal 中,它也只会创建 10 个对象,即使要执行 1000 次时间格式化任务,依然只会新建 10 个 SimpleDateFormat 对象,每个线程调用自己的 ThreadLocal 变量。

2.ThreadLocal 基础使用

ThreadLocal 常用的核心方法有三个:

  1. set 方法:用于设置线程独立变量副本。没有 set 操作的 ThreadLocal 容易引起脏数据。
  2. get 方法:用于获取线程独立变量副本。没有 get 操作的 ThreadLocal 对象没有意义。
  3. remove 方法:用于移除线程独立变量副本。没有 remove 操作容易引起内存泄漏。

ThreadLocal 所有方法如下图所示:

threadlocal的缺点,threadlocal应用场景(7)

官方说明文档:https://docs.oracle.com/javase/8/docs/api/

ThreadLocal 基础用法如下:

/** * @公众号:Java中文社群 */ public class ThreadLocalExample { // 创建一个 ThreadLocal 对象 private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { // 线程执行任务 Runnable runnable = new Runnable() { @Override public void run() { String threadName = Thread.currentThread().getName(); System.out.println(threadName " 存入值:" threadName); // 在 ThreadLocal 中设置值 threadLocal.set(threadName); // 执行方法,打印线程中设置的值 print(threadName); } }; // 创建并启动线程 1 new Thread(runnable, "MyThread-1").start(); // 创建并启动线程 2 new Thread(runnable, "MyThread-2").start(); } /** * 打印线程中的 ThreadLocal 值 * @param threadName 线程名称 */ private static void print(String threadName) { try { // 得到 ThreadLocal 中的值 String result = threadLocal.get(); // 打印结果 System.out.println(threadName " 取出值:" result); } finally { // 移除 ThreadLocal 中的值(防止内存溢出) threadLocal.remove(); } } }

以上程序的执行结果为:

threadlocal的缺点,threadlocal应用场景(8)

上一页12345下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.