• ThreadLocal 详解


    转自:https://www.cnblogs.com/renyuanwei/p/9635235.html

    什么是ThreadLocal

        根据JDK文档中的解释:ThreadLocal的作用是提供线程内的局部变量,这种变量在多线程环境下访问时能够保证各个线程里变量的独立性。

        从这里可以看出,引入ThreadLocal的初衷是为了提供线程内的局部变量

    ThreadLocal 不是一个线程,而是一个线程的本地化对象。当某个变量在使用 ThreadLocal 进行维护时,ThreadLocal 为使用该变量的每个线程分配了一个独立的变量副本。

    每个线程可以自行操作自己对应的变量副本,而不会影响其他线程的变量副本。

    API 方法

    ThreadLocal 的 API 提供了如下的 4 个方法。

    1)protected T initialValue()

    返回当前线程的局部变量副本的变量初始值。


    2)T get()

    返回当前线程的局部变量副本的变量值,如果此变量副本不存在,则通过 initialValue() 方法创建此副本并返回初始值。


    3)void set(T value)

    设置当前线程的局部变量副本的变量值为指定值。


    4)void remove()

    删除当前线程的局部变量副本的变量值。


    在实际使用中,我们一般都要重写 initialValue() 方法,设置一个特定的初始值。

    关于initialValue的初始化。本人尝试了多种方式:

    1
    2
    3
    4
    5
    6
    7
    8
    //new ThreadLocal方式:不推荐
           final ThreadLocal<String> commandThreads = new ThreadLocal<String>() {
               @Override
               protected String initialValue() {
                   return "execute :"+System.currentTimeMillis();
               }
           };
           System.out.println(commandThreads.get());

      

    1
    2
    3
    4
    5
    //withInitial方式:
            ThreadLocal<String> commandThreadnew =
    //             ThreadLocal.withInitial(()-> "execute :"+System.currentTimeMillis());
                    ThreadLocal.withInitial(()->new String("execute :"+System.currentTimeMillis()));
            System.out.println(commandThreadnew.get());

      

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //(new Supplier<String>(){}方式 推荐
           ThreadLocal<String> commandThreadnew1 =
                   ThreadLocal.withInitial(new Supplier<String>() {
                       @Override
                       public String get() {
                           return  "execute :"+System.currentTimeMillis();
                       }
                   });
     
           System.out.println(  commandThreadnew1.get());

      

    以下是关于ThreadLocal 解决多线程变量共享问题

    存在争议点:

    ThreadLocal到底能不能解决共享对象的多线程访问问题?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package com.wuxianjiezh.demo.threadpool;
     
    public class MainTest {
     
        public static void main(String[] args) {
            Bank bank = new Bank();
            Thread xMThread = new Thread(() -> bank.deposit(200), "小明");
            Thread xGThread = new Thread(() -> bank.deposit(200), "小刚");
            Thread xHThread = new Thread(() -> bank.deposit(200), "小红");
            xMThread.start();
            xGThread.start();
            xHThread.start();
        }
    }
     
    class Bank {
     
        private int money = 1000;
     
        public void deposit(int money) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "--当前账户余额为:" this.money);
            this.money += money;
            System.out.println(threadName + "--存入 " + money + " 后账户余额为:" this.money);
            try {
                Thread.sleep(1000);
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

      运行结果:存在多线程输出结果混乱

    1
    2
    3
    4
    5
    6
    小明--当前账户余额为:1000
    小红--当前账户余额为:1000
    小红--存入 200 后账户余额为:1400
    小刚--当前账户余额为:1000
    小刚--存入 200 后账户余额为:1600
    小明--存入 200 后账户余额为:1200

      

    使用 ThreadLocal 保存对象的局部变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class MainTest {
     
        public static void main(String[] args) {
            Bank bank = new Bank();
            Thread xMThread = new Thread(() -> bank.deposit(200), "小明");
            Thread xGThread = new Thread(() -> bank.deposit(200), "小刚");
            Thread xHThread = new Thread(() -> bank.deposit(200), "小红");
            xMThread.start();
            xGThread.start();
            xHThread.start();
        }
    }
     
    class Bank {
     
        // 初始化账户余额为 100
        ThreadLocal<Integer> account = ThreadLocal.withInitial(new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 1000;
            }
        });
     
        public void deposit(int money) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "--当前账户余额为:" + account.get());
            account.set(account.get() + money);
            System.out.println(threadName + "--存入 " + money + " 后账户余额为:" + account.get());
            try {
                Thread.sleep(1000);
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

      运行结果为:

    1
    2
    3
    4
    5
    6
    7
    小明--当前账户余额为:1000
    小红--当前账户余额为:1000
    小红--存入 200 后账户余额为:1200
    小刚--当前账户余额为:1000
    小刚--存入 200 后账户余额为:1200
    小明--存入 200 后账户余额为:1200
    可以看到,我们要的效果达到了。各线程间同时操作自己的变量,相互间没有影响。

      

    ThreadLocal 与 Thread 同步机制的比较

    • 同步机制采用了以时间换空间方式,通过对象锁保证在同一个时间,对于同一个实例对象,只有一个线程访问。

    • ThreadLocal 采用以空间换时间方式,为每一个线程都提供一份变量,各线程间同时访问互不影响。

  • 相关阅读:
    【U-Boot】建立U-Boot编译环境
    【电路】JTAG下载器研究
    【FPGA】Xilinx-7系的时钟资源与DDR3配置
    【电路】KiCad-Pcbnew-建BGA形式的Footprint
    【电路】KiCad-Eeschema-建BGA形式的Symbol
    【电路】差分接口互连(二)
    【电路】差分接口互连(一)
    【电路】pmic芯片设计细节
    【电路】PADS建库细节
    【电路】SPI接口细化&控制
  • 原文地址:https://www.cnblogs.com/sharpest/p/10884823.html
Copyright © 2020-2023  润新知