<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
幾乎每個 Java 應用程式都使用執行緒。像 Tomcat 這樣的 Web 伺服器在單獨的工作執行緒中處理每個請求,胖使用者端在專用工作執行緒中處理長時間執行的請求,甚至批次處理使用 java.util.concurrent.ForkJoinPool 來提高效能。
因此,有必要以執行緒安全的方式編寫類,這可以通過以下技術之一來實現。
當多個執行緒存取同一個範例或靜態變數時,您必須以某種方式協調對該變數的存取。最簡單的方法就是避免使用範例或靜態變數。沒有範例變數的類中的方法只使用區域性變數和方法引數。下面的例子展示了這樣一個方法,它是類 java.lang.Math 的一部分:
public static int subtractExact(int x, int y) { int r = x - y; if (((x ^ y) & (x ^ r)) < 0) { throw new ArithmeticException("integer overflow"); } return r; }
如果您無法避免狀態,請不要共用狀態。狀態應該只由單個執行緒擁有。這種技術的一個例子是 SWT 或 Swing 圖形化使用者介面框架的事件處理執行緒。
您可以通過擴充套件執行緒類並新增範例變數來實現執行緒區域性範例變數。在以下範例中,欄位 pool 和 workQueue 對於單個工作執行緒是原生的。
package java.util.concurrent; public class ForkJoinWorkerThread extends Thread { final ForkJoinPool pool; final ForkJoinPool.WorkQueue workQueue; }
實現執行緒區域性變數的另一種方法是將類 java.lang.ThreadLocal 用於要使執行緒區域性的欄位。下面是一個使用 java.lang.ThreadLocal 的範例變數範例:
public class CallbackState { public static final ThreadLocal<CallbackStatePerThread> callbackStatePerThread = new ThreadLocal<CallbackStatePerThread>() { @Override protected CallbackStatePerThread initialValue() { return getOrCreateCallbackStatePerThread(); } }; }
您將範例變數的型別包裝在 java.lang.ThreadLocal 中。您可以通過方法 initialValue() 為您的 java.lang.ThreadLocal 提供初始值。
下面展示瞭如何使用範例變數:
CallbackStatePerThread callbackStatePerThread = CallbackState.callbackStatePerThread.get();
通過呼叫 get() 方法,您會收到與當前執行緒關聯的物件。
由於在應用程式伺服器中,使用許多執行緒池來處理請求,因此 java.lang.ThreadLocal 會導致此環境中的記憶體消耗很高。因此,不建議將 java.lang.ThreadLocal 用於由應用程式伺服器的請求處理執行緒執行的類。
如果您不使用上述技術共用狀態,則需要一種執行緒進行通訊的方式。做到這一點的一種技術是線上程之間傳遞訊息。您可以使用 java.util.concurrent 包中的並行佇列實現訊息傳遞。或者,更好的是,使用Akka 之類的框架,這是一個演員風格並行的框架。以下範例顯示瞭如何使用 Akka 傳送訊息:
target.tell(message, getSelf());
並收到一條訊息:
@Override public Receive createReceive() { return receiveBuilder() .match(String.class, s -> System.out.println(s.toLowerCase())) .build(); }
為了避免傳送執行緒在另一個執行緒讀取訊息時更改訊息的問題,訊息應該是不可變的。因此,Akka 框架的約定是所有訊息都必須是不可變的
當你實現一個不可變類時,你應該將它的欄位宣告為 final。這不僅可以確保編譯器可以檢查這些欄位實際上是不可變的,而且即使它們被錯誤地釋出,也可以使它們正確初始化。這是最終範例變數的範例:
public class ExampleFinalField { private final int finalField; public ExampleFinalField(int value) { this.finalField = value; } }
訊息傳遞使用並行佇列進行執行緒之間的通訊。並行佇列是 java.util.concurrent 包中提供的資料結構之一。這個包提供了並行對映、佇列、出隊、集合和列表的類。這些資料結構經過高度優化和執行緒安全測試。
如果您不能使用上述技術之一,請使用同步鎖。通過將鎖放在同步塊中,您可以確保一次只有一個執行緒可以執行此部分。
synchronized(lock) { i++; }
請注意,當您使用多個巢狀同步塊時,可能會出現死鎖。當兩個執行緒試圖獲取另一個執行緒持有的鎖時,就會發生死鎖。
正常的非易失性欄位可以快取在暫存器或快取中。通過將變數宣告為 volatile,您可以告訴JVM和編譯器始終返回最新寫入的值。這不僅適用於變數本身,還適用於執行緒寫入 volatile 欄位的所有值。下面顯示了一個 volatile 範例變數的範例:
public class ExampleVolatileField { private volatile int volatileField; }
如果寫入不依賴於當前值,您可以使用 volatile 欄位。或者,如果您可以確保一次只有一個執行緒可以更新該欄位。
到此這篇關於建立Java執行緒安全類的七種方法的文章就介紹到這了,更多相關Java執行緒安全類建立內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45