版权声明:本文由吴仙杰创做整理,转载请注明出处:http://www.javashuo.com/article/p-siztiazx-mo.htmljava
ThreadLocal
不是一个线程,而是一个线程的本地化对象。当某个变量在使用 ThreadLocal
进行维护时,ThreadLocal
为使用该变量的每一个线程分配了一个独立的变量副本,每一个线程能够自行操做本身对应的变量副本,而不会影响其余线程的变量副本。shell
ThreadLocal
的 API 提供了以下的 4 个方法。segmentfault
1)protected T initialValue()
多线程
返回当前线程的局部变量副本的变量初始值。ide
2)T get()
this
返回当前线程的局部变量副本的变量值,若是此变量副本不存在,则经过 initialValue()
方法建立此副本并返回初始值。线程
3)void set(T value)
code
设置当前线程的局部变量副本的变量值为指定值。对象
4)void remove()
rem
删除当前线程的局部变量副本的变量值。
在实际使用中,咱们通常都要重写 initialValue()
方法,设置一个特定的初始值。
首先,咱们来看看不考虑多线程共享数据的状况。
如今有小明、小刚、小红三人在同一家银行,分别向各自帐户存入 200 元钱:
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(); } } }
运行结果:
小明--当前帐户余额为:1000 小红--当前帐户余额为:1000 小红--存入 200 后帐户余额为:1400 小刚--当前帐户余额为:1000 小刚--存入 200 后帐户余额为:1600 小明--存入 200 后帐户余额为:1200
结果是除了小明存钱和本身帐户余额能对上外,小刚和小红也都只存了 200,但他们的帐户余额分别多了 200 和 400?
这是由于多个线程共享了同一个实例对象的局部变量所致。
使用 ThreadLocal
保存对象的局部变量。
package com.wuxianjiezh.demo.threadpool; import java.util.function.Supplier; 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(); } } }
运行结果:
小明--当前帐户余额为:1000 小红--当前帐户余额为:1000 小红--存入 200 后帐户余额为:1200 小刚--当前帐户余额为:1000 小刚--存入 200 后帐户余额为:1200 小明--存入 200 后帐户余额为:1200
能够看到,咱们要的效果达到了。各线程间同时操做本身的变量,相互间没有影响。
同步机制采用了以时间换空间方式,经过对象锁保证在同一个时间,对于同一个实例对象,只有一个线程访问。
ThreadLocal
采用以空间换时间方式,为每个线程都提供一份变量,各线程间同时访问互不影响。