ThreadLocal

本文详细介绍了ThreadLocal线程封闭技术的概念、原理及使用方法,并通过示例代码展示了如何在多线程环境下安全高效地访问和修改共享变量。重点探讨了ThreadLocal与锁、栈封闭等并发控制手段的区别与优势,强调了ThreadLocal在解决并发访问问题时的独特作用。
摘要由CSDN通过智能技术生成

什么是ThreadLocal,它能做什么

ThreadLocal是Jdk1.2开始提供的一种线程封闭的技术,这个类全包路径 java.lang.ThreadLocal。他使得每一个线程都能拥有ThreadLocal保护的变量的独立副本,在线程内部使用变量时,就如同在方法内部使用局部变量一样不比担心多线程环境下的并发安全性。它常用于防止可变的单实例变量或者全局变量进行共享。

为什么用它

我目前知道的避免并发访问问题有大概这么几种方式:锁(syncronized、Lock)、线程封闭、栈封闭(方法局部变量)。
使用锁来控制全局变量的访问显然存在效率问题;使用栈封闭需要考虑溢出问题(可以类比安全发布的概念),同时变量会在方法内部创建,如果线程执行的多个方法需要访问这个变量,就不好办了。于是,线程封闭可以缓解上面两种技术带来的问题,它使得每个线程都能获取到最原始的被其保护后的变量的值,每个线程对这个全局ThreadLocal变量的修改不会影响到其它变量;并且,这个ThreadLocal变量对线程内执行的所有方法可见,线程执行的方法对其修改只在线程内部有效。

怎么用它

先贴一段代码

public class Portal
{
    class InnerTest
    {
        private int i;

        InnerTest()
        {
            i = 0;
        }
        public int getI()
        {
            return i;
        }
        public void setI(int i)
        {
            this.i = i;
        }
    }
    private ThreadLocal<InnerTest>  test1   = new ThreadLocal<InnerTest>()
                                            {
                                                @Override
                                                protected InnerTest initialValue()
                                                {
                                                    return new InnerTest();
                                                };
                                            };
    private ThreadLocal<InnerTest>  test2   = new ThreadLocal<InnerTest>();
    private ThreadLocal<InnerTest>  test    = null;
    private volatile boolean        f1      = false;
    private volatile boolean        f2      = false;

    void main1()
    {
        Thread thread1 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    System.out.println("thread1执行");
                    if (test == null)
                    {
                        throw new RuntimeException();
                    }
                    InnerTest t = test.get();
                    System.out.println("is t null? " + (t == null));
                    t.setI(1);
                    f1 = true;
                    while (true)
                    {
                        if (f2)
                        {
                            System.out.println("thread1 value:" + t.getI());
                            break;
                        }
                    }
                }
            });
        Thread thread2 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    while (true)
                    {
                        if (f1)
                        {
                            System.out.println("thread2执行");
                            if (test == null)
                            {
                                throw new RuntimeException();
                            }
                            InnerTest t = test.get();
                            System.out.println("is t null? " + (t == null));
                            t.setI(2);
                            f2 = true;
                            break;
                        }
                    }
                }
            });
        thread1.start();
        thread2.start();
    }

    void main2()
    {
        Thread thread1 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    System.out.println("thread1执行");
                    if (test == null)
                    {
                        throw new RuntimeException();
                    }
                    InnerTest t = test.get();
                    System.out.println("is t null? " + (t == null));
                    if (t == null)
                    {
                        test.set(new InnerTest());
                        t = test.get();
                    }
                    t.setI(1);
                    f1 = true;
                    while (true)
                    {
                        if (f2)
                        {
                            System.out.println("thread1 value:" + t.getI());
                            break;
                        }
                    }
                }
            });
        Thread thread2 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    while (true)
                    {
                        if (f1)
                        {
                            System.out.println("thread2执行");
                            if (test == null)
                            {
                                throw new RuntimeException();
                            }
                            InnerTest t = test.get();
                            System.out.println("is t null? " + (t == null));
                            t.setI(2);// 此处抛出空指针异常,thread1的赋值操作只在线程内部有效
                            f2 = true;
                            break;
                        }
                    }
                }
            });
        thread1.start();
        thread2.start();
    }

    public static void main(String[] args)
    {
        Portal portal = new Portal();
        portal.test = portal.test1;
        portal.main1();
        // portal.test = portal.test2;
        // portal.main2();
    }
}

执行结果

thread1执行
is t null? false
thread2执行
is t null? false
thread1 value:1

以上代码演示了ThreadLocal基本使用方法,从里面可以得到这些信息:

  1. 如何创建ThreadLocal变量
  2. 如何访问ThreadLocal变量
    通过get方法
  3. ThreadLocal变量两种初始化方法
    · 创建ThreadLocal变量时重写其initialValue方法
    · 直接new出ThreadLocal变量,在线程内部首次使用时,首先判断是否为空,为空则主动设置其值
  4. 两种方式验证,在子线程内部修改主线程全局ThreadLocal变量内的值,修改只对本线程内部有效(不影响其他线程读取到最原始的值)

注意事项

  • ThreadLocal内部使用ThreadLocalMap来保存数据,ThreadLocalMap并不是Map的实现,但是内部存贮数据的也是一个数组(Object数组)。
  • ThreadLocal需要指定泛型类型,否则默认为Object,因此其只可保护引用类型数据。
  • 有兴趣的可以关注它的两个子类java.lang.InheritableThreadLocal和org.springframework.core.NamedThreadLocal
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stillearn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值