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