auto.js停止所有線程_Java線程與并發編程實踐:深入理解volatile和final變量

同步有兩種屬性:互斥性和可見性。synchronized關鍵字與兩者都有關系。Java同時也提供了一種更弱的、僅僅包含可見性的同步形式,并且只以volatile關鍵字關聯。

假設你自己設計了一個停止線程的機制(因為無法使用Thread不安全的stop()方法))。清單1中ThreadStopping程序源碼展示了該如何完成這項任務。

清單1 嘗試停止一個線程

public class ThreadStopping{   public static void main(String[] args)   {      class StoppableThread extends Thread      {         private boolean stopped; // defaults to false         @Override         public void run()         {            while(!stopped)               System.out.println("running");         }         void stopThread()         {            stopped = true;         }      }      StoppableThread thd = new StoppableThread();      thd.start();      try      {         Thread.sleep(1000); // sleep for 1 second      }      catch (InterruptedException ie)      {      }      thd.stopThread();   } }

清單2中的main()方法聲明了一個叫做StoppableThread的本地類,它繼承自Thread。在初始化完StoppableThread之后,默認的主線程啟動和這個 Thread對象關聯的線程。之后它睡眠 1 秒,并且在死亡之前調用StoppableThread的stop()方法。

StoppableThread聲明了一個被初始化為false的stopped實例變量,stopThread()方法會將該變量設置為true,同時run()方法中的while循環會在每次迭代中檢查stopped的值是否已經修改為true。

照下面編譯清單2:

javac ThreadStopping.java

運行程序:

java ThreadStopping 你應該能觀測到一系列運行時的消息。

當你在單處理器/單核的機器上運行這個程序的時候,很可能會觀測到程序停止。但是在一個多處理器的機器或多核單處理器的機器上,可能就看不到程序停止,因為每個處理器或者核心很可能有自己的一份stopped的拷貝,當一條線程修改了自己的拷貝,其他線程的拷貝并沒有被改變。

你或許決定使用synchronized關鍵字以確保只能訪問主存中的stopped變量。然后經過一番思考,你決定在清單3中使用同步訪問一對臨界區的方式來解決這個問題。

清單3 嘗試使用synchronized來停止一個線程

public class ThreadStopping{   public static void main(String[] args)   {      class StoppableThread extends Thread      {         private boolean stopped; // defaults to false         @Override         public void run()         {            synchronized(this)            {               while(!stopped)                  System.out.println("running");            }          }         synchronized void stopThread()         {            stopped = true;         }      }      StoppableThread thd = new StoppableThread();      thd.start();      try      {         Thread.sleep(1000); // sleep for 1 second      }      catch (InterruptedException ie)      {      }      thd.stopThread();   }}

出于兩個因素考慮,清單3不是一個好主意。盡管你只需解決可見性的問題,synchronized卻同時解決了互斥的問題(在該程序中不是個問題)。更重要的是,你還往程序中引進了另一個更嚴重的問題。

你已經正確地對stopped進行了同步訪問,但是進一步觀察run()方法中的同步塊,尤其是這個while循環。由于正在執行循環的這個線程已經獲取了當前StoppableThread對象(通過synchronized(this))的鎖,這個循環不會終止。因為默認的主線程需要獲取相同的鎖,所以它在該對象上調用stopThread()方法的任意嘗試都會導致自己被阻塞住。

你可以使用局部變量并在同步塊中將stopped的值賦給這個變量來解決這一問題,如下所示:

public void run(){   boolean _stopped = false;   while (!_stopped)   {      synchronized(this)      {         _stopped = stopped;      }      System.out.println("running");   }}

不過,每次循環迭代都要嘗試獲取鎖的方式會存在性能開銷(還不如以前),所以這個解決方式是得不償失的。清單4展示了一個更為高效且整潔的方法。

清單4 嘗試通過volatile關鍵字來停止一個線程

public class ThreadStopping{   public static void main(String[] args)   {      class StoppableThread extends Thread      {         private #####volatile boolean stopped; // defaults to false         @Override         public void run()         {            while(!stopped)               System.out.println("running");         }         void stopThread()         {            stopped = true;         }      }      StoppableThread thd = new StoppableThread();      thd.start();      try      {         Thread.sleep(1000); // sleep for 1 second      }      catch (InterruptedException ie)      {      }      thd.stopThread();   } }

由于stopped已經標記為volatile,每條線程都會訪問主存中該變量的拷貝而不會訪問緩存中的拷貝。這樣,即使在多處理器或者多核的機器上,該程序也會停止。

警告

只有可見性導致問題時,才應該使用volatile。而且,你也只能在屬性聲明處才能使用這個保留字(如果你嘗試將局部變量聲明成volatitle,會收到一個錯誤)。最后,你可以將double和long型的屬性聲明成volatile,但是應該避免在32位的JVM上這樣做,原因是此時訪問一個double或者long型的變量值需要進行兩步操作,若要安全地訪問它們的值,互斥(通過synchronized)是必要的。 當一個屬性變量聲明成volatile,就不能同時被聲明final的。不過,由于Java可以讓你安全地訪問final的屬性而無需同步,這也就不能稱之為一個問題了。為了克服DeadlockDemo中的緩存變量問題,我把lock1和lock2都標記成final,盡管也能將它們標記成volatile的。

以后,你會經常使用final關鍵字來確保在不可變(不會發生改變)類的上下文中線程的安全性。參考清單5。

清單5 借助于final創建一個不可變且線程安全的類

import java.util.Set;import java.util.TreeSet;public final class Planets{   private final Set planets = new TreeSet<>();   public Planets()   {      planets.add("Mercury");      planets.add("Venus");      planets.add("Earth");      planets.add("Mars");      planets.add("Jupiter");      planets.add("Saturn");      planets.add("Uranus");      planets.add("Neptune");   }   public boolean isPlanet(String planetName)   {      return planets.contains(planetName);   }}

清單5展示了一個不可變類Planets,其對象存儲著星球名字的集合。盡管集合是可變的,但這個類的設計卻保證在構造函數退出之后,集合不會再被改變。通過聲明planets為final,這個屬性的引用不能被更改。而且,該引用也不能被緩存,所以緩存變量的問題也不復存在。

關于不可變對象,Java提供了一種特殊的線程安全的保證。即便沒有用同步來發布(暴露)這些對象的引用,它們依然可以被多條線程安全地訪問。不可變對象提供了下列易于識別的規則:

  • 不可變對象絕對不允許狀態變更。
  • 所有的屬性必須聲明成final。
  • 對象必須被恰當地構造出來以防this引用脫離構造函數。

最后一點很讓人迷惑,所以這里給出一個this顯式地脫離構造函數的簡單例子:

public class ThisEscapeDemo{   private static ThisEscapeDemo lastCreatedInstance;   public ThisEscapeDemo()   {      lastCreatedInstance = this;   }}

在www.ibm.com/developerworks/library/j-jtp0618/上查看《Java theory and practice:Safe construction techniques》學習更多常見線程風險的相關知識。


本文節選自《Java線程與并發編程實踐》

72ead4aff594088198d3f522a12dbe60.png

Java線程和并發工具是應用開發中的重要部分,備受開發者的重視,也有一定的學習難度。

本書是針對Java 8中的線程特性和并發工具的快速學習和實踐指南。全書共8章,分別介紹了Thread類和Runnable接口、同步、等待和通知、線程組、定時器框架、并發工具、同步器、鎖框架,以及高級并發工具等方面的主題。每章的末尾都以練習題的方式,幫助讀者鞏固所學的知識。附錄A給出了所有練習題的解答,附錄B給出了一個基于Swing線程的教程。

本書適合有一定基礎的Java程序員閱讀學習,尤其適合想要掌握Java線程和并發工具的讀者閱讀參考。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259113.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259113.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259113.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

項目實例改編:利用structs2的action 實時顯示圖片、pdf和其他內容的框架抽取。(轉)...

轉自&#xff1a;http://www.verydemo.com/demo_c167_i1382.html 針對&#xff1a;預覽文件&#xff08;圖片&#xff0c;PDF&#xff09;文件來源為action中的inputStream 重點&#xff1a; structs2的action的配置 action的寫法和結果類型 resulttype的寫法 網頁上實…

零碎的小知識點 ----------C# ToString()函數注意事項

C#中存在著大量的字符串操作&#xff0c;有專門的string類&#xff0c;各種各種的方法&#xff0c;其中使用最為頻繁的方法為ToString()&#xff0c;用起來很是順手&#xff0c;但是這里存在一個很大的問題&#xff0c;空字符是不能用ToString方法轉換的&#xff0c;不然就會報…

ios越獄系統UIGestureRecognizer事件截獲問題

越獄的機器給self.view設置一個UITapGestureRecognizer,這貨就把所有的點擊事件全截獲了,比如某個按鈕,點擊就沒效果.普通系統是沒有問題的. 因此要給UIGestureRecognizer設置delegate并且在其中對touch的view進行分別處理 比如要讓按鈕功能正常使用: 1 #pragma mark - UIGestu…

開始Go開發之旅-Golang架構師之路系列實戰

2019獨角獸企業重金招聘Python工程師標準>>> 作者: gomaster.me(馮琪超) 系列:Golang架構師之路 巧婦難做無米之炊&#xff0c;golang sdk就是gopher的大米 下載golang 點擊 官網下載golang sdk 根據不同系統&#xff0c;官網下載鏈接會選擇相應的平臺進行鏈接跳轉&…

delete與delete[]的區別

一直對C中的delete和delete[]的區別不甚了解&#xff0c;今天遇到了&#xff0c;上網查了一下&#xff0c;得出了結論。做個備份&#xff0c;以免丟失。 C告訴我們在回收用 new 分配的單個對象的內存空間的時候用 delete&#xff0c;回收用 new[] 分配的一組對象的內存空間的時…

event對應的各種坐標

IE8不支持的PageXY 相對于整個頁面鼠標的位置 包括溢出的部分 event.pageX; event.pageY; 所有瀏覽器支持的&#xff1a; 相對于當前瀏覽器窗口可視區域的坐標event.clientX;event.clientY; 相對于當前屏幕&#xff08;和瀏覽器窗口大小無關&#xff09;的坐標event.screenX;…

安卓9.0官方系統升級包_華為、榮耀公布可升級安卓10.0機型,你的手機在名單之內嗎?...

在近兩個月以前&#xff0c;美方將華為關進了小黑屋&#xff0c;隨后谷歌也將華為旗下的機型移出了安卓10.0升級名單&#xff0c;這一波操作之后&#xff0c;引起了不小的“恐慌”&#xff0c;許多華為用戶也在擔心是否還能正常使用安卓系統服務&#xff0c;不過&#xff0c;讓…

2. Mysql數據庫的入門知識

2. Mysql數據庫的入門知識 &#xff08;1&#xff09;打開Windows系統提供的服務查看相應的服務。 &#xff08;2&#xff09;在Windows任務管理器的進程中查看 &#xff08;3&#xff09;使用命令行管理windows的Mysql數據庫服務。 Net start 服務名 Net stop 服務名 mysql -h…

十月讀書心得

1.sizeof與strlen的區別。 #include <iostream> using namespace std; void main() {cout << sizeof("hello") << endl;}答案&#xff1a; 6原因&#xff1a; “hello”{‘h’,e,l,l,o,\0};共六個字節。 那么sizeof與strlen有什么區別呢&#xff…

nginx php-fpm 輸出php錯誤日志(轉)

nginx是一個web服務器&#xff0c;因此nginx的access日志只有對訪問頁面的記錄&#xff0c;不會有php 的 error log信息。 nginx把對php的請求發給php-fpm fastcgi進程來處理&#xff0c;默認的php-fpm只會輸出php-fpm的錯誤信息&#xff0c;在php-fpm的errors log里也看不到ph…

protobuf的安裝和使用

以下全部基于win7系統。 protobuf是什么&#xff0c;有什么用網上說的已經很多了。這里就是說一下怎么使用。就當給自己做個筆記吧。 .proto文件的語法什么的也請網上查看&#xff0c;挺多的。 第一步&#xff1a; 下載protoc.exe 和 protobuf-java-2.4.1.jar。這里要注意版本區…

win7優化設置_win7藍牙怎么打開?

當電腦需要連接藍牙設備的時候&#xff0c;就需要打開藍牙設置才行。鑒于一些win7的用戶還不知道藍牙功能在哪&#xff0c;win7藍牙怎么打開&#xff0c;故系統圣地分享本篇教程。1、win7藍牙怎么打開?首先要你的電腦支持藍牙功能。如果你的電腦有藍牙功能的話那么在電腦的右下…

Struts2 通配符

在配置<action …./>元素時&#xff0c;需要指定name,class和method屬性&#xff0c;這三個屬性都支持通配符。 例如&#xff1a; 1.<action name ”*Action” class “student.RegisterAction” method “{1}”> 如果用戶請求的URL為loginAction.action,則調用…

Doxygen從零學起———安裝和配置

Doxygen可以為多種語言生成說明文檔&#xff08;從程序的源代碼中提取其中按照約定格式寫的注釋中提取信息&#xff09; 例如C, Objective-C, C#, C, PHP, Python, IDL (Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL, Tcl, D ,從這期開始&#xff0c;我將系…

JAVA Drp項目實戰—— Unable to compile class for JSP 一波三折

交代下背景。電腦系統是64位的&#xff0c;用的是64位的Tomcat。安裝是32位的Myeclipse10&#xff0c;java環境也是32位的。Tomcat在開始啟動時會報這樣一個錯誤&#xff0c;“Cant load IA 64-bit .dll on a AMD32-bit platform”。可是不耽誤使用&#xff0c;近期在敲Drp項目…

Java中的ClassLoader

Java中類的加載過程&#xff08;如Dog類&#xff09;&#xff1a; 通過類型信息定位Dog.class文件。載入Dog.class文件&#xff0c;創建相應的Class對象。執行父類的靜態字段定義時初始化語句和父類的靜態初始化塊。執行子類的靜態字段定義時初始化語句和子類的靜態初始化塊。當…

excel刪除無盡空白行_excel如何批量刪除空白行 巧用 ctrl+G 只需1秒 最常用的技巧...

工作中我們使用excel通常都會遇到這種情況&#xff0c;就是表格中有很多多余的空行。我們需要把多余的空行刪除。 如果空行只有一兩行的話&#xff0c;可以把鼠標放在空白行上&#xff0c;然后點擊鼠標右鍵&#xff0c;在彈出的菜單中選擇刪除菜單。 在彈出的刪除確定窗口中&am…

Doxygen for C++使用說明——注釋代碼一

寫這一節的時候&#xff0c;我在想網上有眾多的參考文獻&#xff0c;外加官網上的&#xff0c;要是我再將它們重復一遍&#xff0c;也沒什么意思。網上資料很多&#xff0c;但是他們有一個共同的缺點是都是羅列用法&#xff0c;然后顯示效果。這些都是比較散的&#xff0c;我想…

DevOps的前世今生

2019獨角獸企業重金招聘Python工程師標準>>> 目前在國外&#xff0c;互聯網巨頭如Google、Facebook、Amazon、LinkedIn、Netflix、Airbnb&#xff0c;傳統軟件公司如Adobe、IBM、Microsoft、SAP等&#xff0c;亦或是網絡業務非核心企業如蘋果、沃爾瑪、索尼影視娛樂…

【轉】最牛B的編碼套路

最近&#xff0c;我大量閱讀了Steve Yegge的文章。其中有一篇叫“Practicing Programming”&#xff08;練習編程&#xff09;&#xff0c;寫成于2005年&#xff0c;讀后令我驚訝不已&#xff1a; 與你所相信的恰恰相反&#xff0c;單純地每天埋頭于工作并不能算是真正意義上的…