摘要:提供了線程安全的共享對(duì)象,在編寫(xiě)多線程代碼時(shí),可把不安全的整個(gè)變量封裝進(jìn),或者把該對(duì)象與線程相關(guān)的狀態(tài)使用保存并不能替代同步機(jī)制,兩者面向的問(wèn)題領(lǐng)域不同。
ThreadLocal類
使用ThreadLocal類可以簡(jiǎn)化多線程編程時(shí)的并發(fā)訪問(wèn),使用這個(gè)工具類可以很簡(jiǎn)捷地隔離多線程程序的競(jìng)爭(zhēng)資源。Java5之后,為ThreadLocal類增加了泛型支持,即ThreadLocal
ThreadLocal,是Thread Local Variable (線程局部變量) 的意思。功能就是為每一個(gè)使用該變量的線程都提供一個(gè)變量值的副本,使每一個(gè)線程都可以獨(dú)立的改變自己的副本,而不會(huì)與其他線程的副本沖突。從線程的角度看,就好像每一個(gè)線程都完全擁有該變量一樣
ThreadLocal類的三個(gè)public方法:
T get():返回此線程局部變量中當(dāng)前線程副本中的值
void remove():刪除此線程局部變量中當(dāng)前線程的值
void set(T value):設(shè)置此線程局部變量中當(dāng)前線程副本中的值
class Account { /* 定義一個(gè)ThreadLocal類型的變量,該變量將是一個(gè)線程局部變量 每個(gè)線程都會(huì)保留該變量的一個(gè)副本 */ private ThreadLocalname = new ThreadLocal<>(); // 定義一個(gè)初始化name成員變量的構(gòu)造器 public Account(String str) { this.name.set(str); // 下面代碼用于訪問(wèn)當(dāng)前線程的name副本的值 System.out.println("---" + this.name.get()); } // name的setter和getter方法 public String getName() { return name.get(); } public void setName(String str) { this.name.set(str); } } class MyTest extends Thread { // 定義一個(gè)Account類型的成員變量 private Account account; public MyTest(Account account, String name) { super(name); this.account = account; } public void run() { // 循環(huán)10次 for (int i = 0 ; i < 10 ; i++) { // 當(dāng)i == 6時(shí)輸出將賬戶名替換成當(dāng)前線程名 if (i == 6) { account.setName(getName()); } // 輸出同一個(gè)賬戶的賬戶名和循環(huán)變量 System.out.println(account.getName() + " 賬戶的i值:" + i); } } } public class ThreadLocalTest { public static void main(String[] args) { // 啟動(dòng)兩條線程,兩條線程共享同一個(gè)Account Account at = new Account("初始名"); /* 雖然兩條線程共享同一個(gè)賬戶,即只有一個(gè)賬戶名 但由于賬戶名是ThreadLocal類型的,所以每條線程 都完全擁有各自的賬戶名副本,所以從i == 6之后,將看到兩條 線程訪問(wèn)同一個(gè)賬戶時(shí)看到不同的賬戶名。 */ new MyTest(at, "線程甲").start(); new MyTest(at, "線程乙").start (); } }
上述程序,由于其中的賬戶名是一個(gè)ThreadLocal變量,所以雖然程序中只有一個(gè)Account對(duì)象,但兩個(gè)子線程將會(huì)產(chǎn)生兩個(gè)賬戶名(主線程持有一個(gè)賬戶名的副本)。程序?qū)嶋H上賬戶名有三個(gè)副本,主線程一個(gè),另外啟動(dòng)的兩個(gè)線程各一個(gè),它們的值互不干擾,每個(gè)線程完全擁有自己的ThreadLocal變量
ThreadLocal將需要并發(fā)訪問(wèn)的資源復(fù)制多份,每個(gè)線程擁有一份資源,每個(gè)線程都擁有自己的資源副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步。ThreadLocal提供了線程安全的共享對(duì)象,在編寫(xiě)多線程代碼時(shí),可把不安全的整個(gè)變量封裝進(jìn)ThreadLocal,或者把該對(duì)象與線程相關(guān)的狀態(tài)使用LocalThread保存
ThreadLocal并不能替代同步機(jī)制,兩者面向的問(wèn)題領(lǐng)域不同。同步機(jī)制是為了同步多個(gè)線程對(duì)相同資源的并發(fā)訪問(wèn),是多個(gè)線程之間進(jìn)行通信的有效方式;而ThreadLocal是為了隔離多個(gè)線程的數(shù)據(jù)共享,從根本上避免多個(gè)線程之間對(duì)共享資源的競(jìng)爭(zhēng)
如果多個(gè)線程之間需要共享資源,以達(dá)到線程之間的通信功能就使用同步機(jī)制;如果僅僅需要隔離多個(gè)線程之間的共享沖突,則可以使用ThreadLocal
包裝線程不安全的集合對(duì)于Set、List、Queue和Map四種集合,最常用的是HashSet、TreeSet、ArrayList、ArrayQueue、LinkedList和HashMap、TreeMap等實(shí)現(xiàn)類。其中Vector、HashTable、Properties是線程安全的。其中ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是線程不安全的,當(dāng)多個(gè)并發(fā)向這些集合中存、取元素時(shí),就可能會(huì)破壞這些集合的數(shù)據(jù)完整性
使用Collections提供的類方法把這些集合包裝成線程安全的集合。Collections提供了如下幾個(gè)靜態(tài)方法:
static
static
static
static
static
例如需要在多線程里使用線程安全的HashMap對(duì)象(如果需要把某個(gè)集合包裝成線程安全的集合,則應(yīng)該在創(chuàng)建之后立即包裝,如下程序所示),則可以采用如下代碼:
// 使用Collections 的 synchronizedMap 方法將一個(gè)普通的HashMap包裝成線程安全的類 HashMap m = Collections.synchronizedMap(new HashMap());線程安全的集合類
java.util.concurrent包下提供了大量支持高效并發(fā)訪問(wèn)的集合接口和實(shí)現(xiàn)類:
線程安全的集合類可以分為兩類:
以Concurrent開(kāi)頭的集合類,如ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue和ConcurrentLinkedDeque
以CopyOnWrite開(kāi)頭的集合類,如CopyOnWriteArrayList、CopyOnWriteArraySet
Concurrent開(kāi)頭的集合類其中以Concurrent開(kāi)頭的集合類代表了支持并發(fā)訪問(wèn)的集合,它們可以支持多個(gè)線程并發(fā)寫(xiě)入訪問(wèn),這些寫(xiě)入線程的所有操作都是線程安全的,但讀取操作不必鎖定
當(dāng)多個(gè)線程共享訪問(wèn)一個(gè)公共集合時(shí),ConcurrentLinkedQueue是一個(gè)恰當(dāng)?shù)倪x擇。它不允許null元素,實(shí)現(xiàn)了多線程的高效訪問(wèn),多個(gè)線程訪問(wèn)ConcurrentLinkedQueue集合時(shí)無(wú)需等待
在默認(rèn)情況下,ConcurrentHashMap支持16個(gè)線程并發(fā)寫(xiě)入,當(dāng)有超過(guò)16 個(gè)線程并發(fā)向該Map 中寫(xiě)入數(shù)據(jù)時(shí),可能有一些線程需要等待。程序通過(guò)設(shè)置concurrentLevel構(gòu)造參數(shù)(默認(rèn)值為16)來(lái)支持更多的并發(fā)寫(xiě)入線程
CopyOnWrite開(kāi)頭的集合類由于CopyOnWriteArraySet底層封裝的是CopyOnWriteArrayList, 因此他的實(shí)現(xiàn)機(jī)制完全類似于CopyOnWriteArrayList
CopyOnWriteArrayList采用復(fù)制底層數(shù)組的方式來(lái)實(shí)現(xiàn)寫(xiě)操作
當(dāng)線程對(duì)CopyOnWriteArrayList集合執(zhí)行讀取操作時(shí), 線程會(huì)直接讀取集合本身, 無(wú)須加鎖和阻塞
當(dāng)線程對(duì)CopyOnWriteArrayList集合執(zhí)行寫(xiě)入操作(add/remove/set)時(shí), 該集合會(huì)在底層復(fù)制一份新的數(shù)組, 然后對(duì)新的數(shù)組執(zhí)行寫(xiě)入操作。由于對(duì)CopyOnWriteArrayList的寫(xiě)入是針對(duì)副本執(zhí)行, 因此它是線程安全的
注意: 由于CopyOnWriteArrayList的寫(xiě)入操作需要頻繁的復(fù)制數(shù)組,因此寫(xiě)入性能較差;但由于讀操作不用加鎖(不是同一個(gè)數(shù)組),因此讀操作非常快。綜上所述,CopyOnWriteArrayList適合在讀取操作遠(yuǎn)遠(yuǎn)大于寫(xiě)操作的場(chǎng)景中, 如緩存等
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66735.html
摘要:典型應(yīng)用鎖和同步器框架的核心類,就是通過(guò)調(diào)用和實(shí)現(xiàn)線程的阻塞和喚醒的,而的方法實(shí)際是調(diào)用的方式來(lái)實(shí)現(xiàn)。 前言 Unsafe是位于sun.misc包下的一個(gè)類,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問(wèn)系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,這些方法在提升Java運(yùn)行效率、增強(qiáng)Java語(yǔ)言底層資源操作能力方面起到了很大的作用。但由于Unsafe類使Java語(yǔ)言擁有了類似C語(yǔ)言指針...
摘要:程序計(jì)數(shù)器程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。它的主要缺點(diǎn)有兩個(gè)一個(gè)是效率問(wèn)題,標(biāo)記和清除過(guò)程的效率都不 Jvm 相關(guān) 類加載機(jī)制 本段參考 http://www.importnew.com/2374... 類加載概念 類加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)ja...
摘要:能否聲明一個(gè)內(nèi)容為空的接口可以。能否將接口聲明為不允許,這樣做會(huì)導(dǎo)致編譯錯(cuò)誤。當(dāng)異常沒(méi)有被捕獲時(shí),會(huì)發(fā)生什么當(dāng)前線程所在的線程組會(huì)執(zhí)行一個(gè)叫的方法,最后程序會(huì)異常退出。非靜態(tài)內(nèi)部類可以使用哪些修飾符非靜態(tài)內(nèi)部類可以使用或修飾符。 原文地址 http://www.instanceofjava.com/2014/12/core-java-interview-questions.html 1...
摘要:多線程編程這篇文章分析了多線程的優(yōu)缺點(diǎn),如何創(chuàng)建多線程,分享了線程安全和線程通信線程池等等一些知識(shí)。 中間件技術(shù)入門教程 中間件技術(shù)入門教程,本博客介紹了 ESB、MQ、JMS 的一些知識(shí)... SpringBoot 多數(shù)據(jù)源 SpringBoot 使用主從數(shù)據(jù)源 簡(jiǎn)易的后臺(tái)管理權(quán)限設(shè)計(jì) 從零開(kāi)始搭建自己權(quán)限管理框架 Docker 多步構(gòu)建更小的 Java 鏡像 Docker Jav...
摘要:本文是作者自己對(duì)中線程的狀態(tài)線程間協(xié)作相關(guān)使用的理解與總結(jié),不對(duì)之處,望指出,共勉。當(dāng)中的的數(shù)目而不是已占用的位置數(shù)大于集合番一文通版集合番一文通版垃圾回收機(jī)制講得很透徹,深入淺出。 一小時(shí)搞明白自定義注解 Annotation(注解)就是 Java 提供了一種元程序中的元素關(guān)聯(lián)任何信息和著任何元數(shù)據(jù)(metadata)的途徑和方法。Annotion(注解) 是一個(gè)接口,程序可以通過(guò)...
閱讀 2195·2023-04-25 20:45
閱讀 1103·2021-09-22 15:13
閱讀 3679·2021-09-04 16:48
閱讀 2603·2019-08-30 15:53
閱讀 961·2019-08-30 15:44
閱讀 986·2019-08-30 15:43
閱讀 1038·2019-08-29 16:33
閱讀 3459·2019-08-29 13:08