免费观看又色又爽又黄的小说免费_美女福利视频国产片_亚洲欧美精品_美国一级大黄大色毛片

java線程封閉的方法是什么-創新互聯

本篇內容主要講解“java線程封閉的方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“java線程封閉的方法是什么”吧!

堅守“ 做人真誠 · 做事靠譜 · 口碑至上 · 高效敬業 ”的價值觀,專業網站建設服務10余年為成都會所設計小微創業公司專業提供企業網站設計營銷網站建設商城網站建設手機網站建設小程序網站建設網站改版,從內容策劃、視覺設計、底層架構、網頁布局、功能開發迭代于一體的高端網站建設服務。

線程封閉的概念

訪問共享變量時,通常要使用同步,所以避免使用同步的方法就是減少共享數據的使用,這種技術就是線程封閉。

實現線程封閉的方法

1:ad-hoc線程封閉

這是完全靠實現者控制的線程封閉,他的線程封閉完全靠實現者實現。也是最糟糕的一種線程封閉。所以我們直接把他忽略掉吧。

2:棧封閉

棧封閉是我們編程當中遇到的最多的線程封閉。什么是棧封閉呢?簡單的說就是局部變量。多個線程訪問一個方法,此方法中的局部變量都會被拷貝一分兒到線程棧中。所以局部變量是不被多個線程所共享的,也就不會出現并發問題。所以能用局部變量就別用全局的變量,全局變量容易引起并發問題。

3:ThreadLocal封閉

使用ThreadLocal是實現線程封閉的好方法,有興趣的朋友可以研究一下ThreadLocal的源碼,其實我們可以理解ThreadLocal內部維護了一個Map,Map的key是每個線程的名稱,而Map的值就是我們要封閉的對象。每個線程中的對象都對應著Map中一個值,也就是ThreadLocal利用Map實現了對象的線程封閉。

線程封閉詳解

線程封閉:當訪問共享的可變數據時,通常需要同步。一種避免同步的方式就是不共享數據。如果僅在單線程內訪問數據,就不需要同步,這種技術稱為線程封閉(thread confinement)

線程封閉技術一個常見的應用就是JDBC的Connection對象,JDBC規范并沒有要求Connection對象必須是線程安全的,在服務器應用程序中,線程從連接池獲取一個Connection對象,使用完之后將對象返還給連接池。下面介紹幾種線程封閉技術:

1、Ad-hoc線程封閉

Ad-hoc線程封閉是指,維護線程的封閉性的職責完全由程序實現承擔,是非常脆弱的,因此在程序中盡量少使用,一般使用更強的線程封閉技術,比如棧封閉或者ThreadLocal類。

2、棧封閉 

棧封閉是線程封閉的一種特列,在棧封閉中,只能通過局部變量才能訪問對象。局部變量的固有屬性之一就是封閉在執行棧中,其他線程無法訪問這個棧,棧封閉也稱為線程內部使用或者線程局部使用。簡單的說就是局部變量。多個線程訪問一個方法,此方法中的局部變量都會被拷貝一分兒到線程棧中。所以局部變量是不被多個線程所共享的,也就不會出現并發問題。所以能用局部變量就別用全局的變量,全局變量容易引起并發問題。

比如下面的例子:

public int loadTheArk(Collection<Animal> candidates) {     SortedSet<Animal> animals;     int numPairs = 0;     Animal candidate = null;          //animals被封裝在方法中,不要使它們溢出     animals = new TreeSet<Animal>(new SpeciesGenderComparator());     animals.addAll(candidates);     for(Animal a:animals){       if(candidate==null || !candidate.isPotentialMate(a)){         candidate = a;       }else{         ark.load(new AnimalPair(candidate,a));         ++numPairs;         candidate = null;       }     }     return numPairs; }

在loadTheArk中實例化一個TreeSet對象,并將該對象的一個引用保存到animals中。此時,只有一個引用指向集合animals,這個引用被封閉到局部變量中,因此也被封閉到局部變量中。然而,如果發布了對集合animals(或者該對象中的任何內部數據)的引用,那么封閉性將被破壞,并導致對象animals的逸出。

3、ThreadLocal類

維持線程封閉性的一種更加規范方法是使用ThreadLocal類,這個類能使線程中某個值與保存值的對象關聯起來。ThreadLocal類提供了get和set等訪問接口或者方法,這些方法為每個使用該變量的線程都存在一份獨立的副本,因此get總是放回當前執行線程在調用set設置的新值??匆幌孪旅娲a例子:

public class ConnectionManager {    private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {     public Connection initialValue() {       Connection conn = null;       try {         conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "username", "password");       } catch (SQLException e) {         e.printStackTrace();       }       return conn;     }   };    public static Connection getConnection() {     return connectionHolder.get();   }    public static void setConnection(Connection conn) {     connectionHolder.set(conn);   } }

通過調用ConnectionManager.getConnection()方法,每個線程獲取到的,都是自己獨立擁有的一個的Connection對象副本,第一次獲取時,是通過initialValue()方法的返回值來設置值的。通過ConnectionManager.setConnection(Connection conn)方法設置的Connection對象,也只會和當前線程綁定。這樣就實現了Connection對象在多個線程中的完全隔離。在Spring容器中管理多線程環境下的Connection對象時,采用的思路和以上代碼非常相似。

每個線程是怎么和Connection對象副本綁定的?這個對象副本保存在哪里。當某個線程初次調用ThreadLocal類的get方法時,就會調用initialValue來獲取初始值,從概念上看,我們可以將ThreadLocal<T>視為包含了Map<thread, T>對象,其中保存了特定于該線程的值,但是ThreadLocal的實現并非如此,這樣只是為了我們方便理解而已。

下面我們來分析一下ThreadLocal類的源碼。ThreadLocal類的方法很簡單,只有四個,分別為set,get,remove, initialValue,從字面上我們也能理解這些方法的作用。

public T get():返回當前線程所對應的局部變量。

public void set(T arg0):設置當前線程局部變量的值?! ?/p>

public void remove():將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。注意,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快內存回收的速度。

protected T initialValue(): 對當線程局部變量進行初始化,并返回該初始值。是protected 屬性,顯然是讓子類進行對其覆蓋重寫的,只有第一次調用set和get方法時才調用?! ?/p>

下面我們對這四個方法的源碼進行分析,看看ThreadLocal類是如何實現這種“為每個線程提供不同的變量拷貝”。

3.1 set方法

以下是set方法的源碼

public void set(T arg0) {    Thread arg1 = Thread.currentThread();    ThreadLocal.ThreadLocalMap arg2 = this.getMap(arg1);    if (arg2 != null) {      arg2.set(this, arg0);    } else {      this.createMap(arg1, arg0);    }  }

從set方法中可以看到,首先獲取當前線程:Thread arg1 = Thread.currentThread();

再獲取當前線程的ThreadLocalMap:ThreadLocal.ThreadLocalMap arg2 = this.getMap(arg1);

判斷ThreadLocalMap是否為空,不為空,則以鍵值對的形式設置值,key為this,value就是局部變量的副本,this是當前線程持有的ThreadLocal類實例化對象。

假如為空,則通過createMap方法創建。

我們看下getMap和createMap方法的源碼:

ThreadLocal.ThreadLocalMap getMap(Thread arg0) {    return arg0.threadLocals;}void createMap(Thread arg0, T arg1) {    arg0.threadLocals = new ThreadLocal.ThreadLocalMap(this, arg1);  }

從代碼上已經寫的非常清楚,每個線程都有自己的局部變量的副本,該副本是存在ThreadLocalMap 中,其中鍵值就是ThreadLocal類實例化對象。也就是說每個線程都擁有自己的ThreadLocalMap,ThreadLocalMap保存的就是局部變量副本。我們看一下java.lang.Thread源碼。

private static int threadInitNumber;ThreadLocalMap threadLocals = null;ThreadLocalMap inheritableThreadLocals = null;

3.2 get方法

public T get() {    Thread arg0 = Thread.currentThread();    ThreadLocal.ThreadLocalMap arg1 = this.getMap(arg0);    if (arg1 != null) {      ThreadLocal.ThreadLocalMap.Entry arg2 = arg1.getEntry(this);      if (arg2 != null) {        Object arg3 = arg2.value;        return arg3;      }    }    return this.setInitialValue();}

從代碼上看,前兩步和set方法是一個樣的,分別獲取當前線程和當前線程的ThreadLocalMap,第三步判斷ThreadLocalMap是否為空,不為空根據this鍵值獲取value,為空調用setInitialValue()方法。

以下是setInitialValue方法代碼:

private T setInitialValue() {    Object arg0 = this.initialValue();    Thread arg1 = Thread.currentThread();    ThreadLocal.ThreadLocalMap arg2 = this.getMap(arg1);    if (arg2 != null) {      arg2.set(this, arg0);    } else {      this.createMap(arg1, arg0);    }    return arg0;}

在setInitialValue里調用了initialValue()方法,也就是子類要重寫覆蓋的方法,對應上面的例子的代碼是:

protected Connection initialValue() {       Connection conn = null;       try {         conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "username", "password");       } catch (SQLException e) {         e.printStackTrace();       }       return conn; }

然后獲取當前線程和當前線程的ThreadLocalMap,ThreadLocalMap為空則調用createMap,否則調用set方法。

到此,相信大家對“java線程封閉的方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是創新互聯建站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

本文題目:java線程封閉的方法是什么-創新互聯
本文網址:http://m.newbst.com/article0/dgjeoo.html

成都網站建設公司_創新互聯,為您提供用戶體驗營銷型網站建設、網站建設定制開發網站設計公司軟件開發

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

外貿網站制作