深入研究 Java ThreadLocal
來源: Devgenios 今天您將了解 ThreadLocal,它是開發 Java 應用程式時使用的常用類別之一。什麼是ThreadLocal?
ThreadLocal類別儲存線程的局部變數。這些變數在不同執行緒之間是隔離的,只能被自己的執行緒存取。ThreadLocal的用例:- 隔離線程之間的資料。
- 資料庫連線的會話管理。
- 儲存線程事務資訊。
如何使用ThreadLocal?
讓我們來看一個簡單的例子。public static void main(String[] args) {
//Создаем ThreadLocal
ThreadLocal<String> local = new ThreadLocal<>();
//Создаем новый класс Random
Random random = new Random();
//Создаем 5 потоков
IntStream.range(0, 5).forEach(a-> new Thread(()-> {
//Присваиваем meaning каждому потоку
local.set(a+" "+random.nextInt(100));
System.out.println("Thread number and its local value "+ local.get());
}).start());
}
在上面的程式碼中,我們創建了一個ThreadLocal類,創建了5個線程,在每個線程中為ThreadLocal賦值並列印。輸出時我們得到:
引擎蓋下是什麼?
如果你仔細觀察,從這個程式碼範例你可以看到ThreadLocal中有兩個重要的方法。-
公共 T get() {}
-
public void set(T值){}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
setter 方法首先取得目前線程,並呼叫getMap()方法取得ThreadLocalMap類別。如果map存在,則以目前流t為key,輸入參數為value,將{key:value}對設為map。如果沒有,則建立一個地圖。現在你可能有一個問題 - 什麼是ThreadLocalMap?
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
ThreadLocalMap是ThreadLocal中的一個內部靜態類,它定義了一個Entry類別來儲存資料。Entry使用ThreadLocal實例作為鍵並設定我們傳遞的值。如果這聽起來太令人困惑,請記住,實際儲存值的是ThreadLocalMap中的Entry類別。為了從ThreadLocal取得數據,我們使用getter方法:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
在getter方法中,我們將使用currentThread作為鍵來取得ThreadLocalMap。然後map會根據ThreadLocal實例getEntry()並傳回Entry實例,然後傳回儲存的值。這裡有一個圖表可以幫助您弄清楚:
-
每個執行緒都維護對ThreadLocalMap 的引用。
-
ThreadLocalMap是ThreadLocal的內部靜態類,使用Entry類別進行儲存。
-
ThreadLocalMap鍵是ThreadLocal 的實例,可以有多個ThreadLocal。
-
ThreadLocal本身不會儲存值,但它是執行緒的關鍵,有助於從ThreadLocalMap取得值。
Java 中的掃描器類
來源:Medium 這篇文章將幫助您熟悉 Java 中的 Scanner 類別。 Java中的Scanner類別是我們想要從使用者那裡取得值時使用的類別。理解它的最簡單方法是透過範例,所以讓我們更清楚地了解它。建立Scanner類別是我們從使用者那裡獲取值所採取的三個步驟之一。第一步是從掃描器類別建立一個物件。Scanner scan=new Scanner(System.in);
現在我們有一個掃描器物件。該物件將具有Scanner類別的 Scanner 屬性。第一步之後,使用者已經可以輸入想要的值,但是如果我們不引導使用者並在控制台或應用程式中顯示該值,那麼在可用性方面就不會很好。因此,最好告知並指導使用者:
System.out.println("Please enter your name");
String name=scan.next();
System.out.println("Your Name:"+name);
在第一行中,我們詢問用戶我們想從他那裡得到什麼。這實際上與掃描器無關,但向用戶提供提示總是好的。在第二行中,我們將分配使用者輸入資料的值並保存它,以便稍後使用。在最後一行中,我們看到我們可以自行決定使用從使用者收到的值。讓我們在程式碼中添加更多細節:
System.out.println("Please enter your last name");
String lastName=scan.next();
System.out.println("Your Name " + name + " " + "Your Last Name" + lastName);
基本上,我們重複前兩行,詢問用戶該值並保存它。現在,在最後一行中,我們使用了從使用者獲得的兩個值,現在將它們一起使用。
GO TO FULL VERSION