版權聲明:本文由吳仙傑創做整理,轉載請註明出處: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
採用以空間換時間方式,爲每個線程都提供一份變量,各線程間同時訪問互不影響。