栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

请介绍一下ThreadLocal?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

请介绍一下ThreadLocal?

ThreadLocal简介

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK中提供的

ThreadLocal
类正是为了解决这样的问题。
ThreadLocal
类主要解决的就是让每个线程绑定自己的值,可以将
ThreadLocal
类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。

如果你创建了一个

ThreadLocal
变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是
ThreadLocal
变量名的由来。他们可以使用
get()
set()
方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。

再举个简单的例子:

比如有两个人去宝屋收集宝物,这两个共用一个袋子的话肯定会产生争执,但是给他们两个人每个人分配一个袋子的话就不会出现这样的问题。如果把这两个人比作线程的话,那么ThreadLocal就是用来这两个线程竞争的。

ThreadLocal示例

相信看了上面的解释,大家已经搞懂 ThreadLocal 类是个什么东西了。

import java.text.SimpleDateFormat;import java.util.Random;public class ThreadLocalExample implements Runnable{     // SimpleDateFormat 不是线程安全的,所以每个线程都要有自己独立的副本    private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd HHmm"));    public static void main(String[] args) throws InterruptedException {        ThreadLocalExample obj = new ThreadLocalExample();        for(int i=0 ; i<10; i++){ Thread t = new Thread(obj, ""+i); Thread.sleep(new Random().nextInt(1000)); t.start();        }    }    @Override    public void run() {        System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());        try { Thread.sleep(new Random().nextInt(1000));        } catch (InterruptedException e) { e.printStackTrace();        }        //formatter pattern is changed here by thread, but it won't reflect to other threads        formatter.set(new SimpleDateFormat());        System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());    }}

Output:

Thread Name= 0 default Formatter = yyyyMMdd HHmmThread Name= 0 formatter = yy-M-d ah:mmThread Name= 1 default Formatter = yyyyMMdd HHmmThread Name= 2 default Formatter = yyyyMMdd HHmmThread Name= 1 formatter = yy-M-d ah:mmThread Name= 3 default Formatter = yyyyMMdd HHmmThread Name= 2 formatter = yy-M-d ah:mmThread Name= 4 default Formatter = yyyyMMdd HHmmThread Name= 3 formatter = yy-M-d ah:mmThread Name= 4 formatter = yy-M-d ah:mmThread Name= 5 default Formatter = yyyyMMdd HHmmThread Name= 5 formatter = yy-M-d ah:mmThread Name= 6 default Formatter = yyyyMMdd HHmmThread Name= 6 formatter = yy-M-d ah:mmThread Name= 7 default Formatter = yyyyMMdd HHmmThread Name= 7 formatter = yy-M-d ah:mmThread Name= 8 default Formatter = yyyyMMdd HHmmThread Name= 9 default Formatter = yyyyMMdd HHmmThread Name= 8 formatter = yy-M-d ah:mmThread Name= 9 formatter = yy-M-d ah:mm

从输出中可以看出,Thread-0已经改变了formatter的值,但仍然是thread-2默认格式化程序与初始化值相同,其他线程也一样。

上面有一段代码用到了创建

ThreadLocal
变量的那段代码用到了 Java8 的知识,它等于下面这段代码,如果你写了下面这段代码的话,IDEA会提示你转换为Java8的格式(IDEA真的不错!)。因为ThreadLocal类在Java 8中扩展,使用一个新的方法
withInitial()
,将Supplier功能接口作为参数。

 private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){        @Override        protected SimpleDateFormat initialValue()        { return new SimpleDateFormat("yyyyMMdd HHmm");        }    };

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/362898.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号