成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 8你了解多少呢?Java之被人遺忘的Java 8的八個功能

開發 后端
一直以來,多線程代碼是服務器開發人員的毒藥。Java的核心庫不斷加入各種復雜的用法來減少訪問共享資源時的線程等待時間。其中之一就是經典的讀寫鎖(ReadWriteLock),它讓你把代碼分成兩部分:需要互斥的寫操作和不需要互斥的讀操作。

一直以來,多線程代碼是服務器開發人員的毒藥(問問Oracle的Java語言架構師和并行開發大師Brian Goetz)。Java的核心庫不斷加入各種復雜的用法來減少訪問共享資源時的線程等待時間。其中之一就是經典的讀寫鎖(ReadWriteLock),它讓你把代碼分成兩部分:需要互斥的寫操作和不需要互斥的讀操作。

表面上看起來很不錯。問題是讀寫鎖有可能是極慢的(最多10倍),這已經和它的初衷相悖了。Java 8引入了一種新的讀寫鎖——叫做時間戳鎖。好消息是這個家伙真的非常快。壞消息是它使用起來更復雜,有更多的狀態需要處理。并且它是不可重入的,這意味著一個線程有可能跟自己死鎖。

時間戳鎖有一種“樂觀”模式,在這種模式下每次加鎖操作都會返回一個時間戳作為某種權限憑證;每次解鎖操作都需要提供它對應的時間戳。如果一個線程在請求一個寫操作鎖的時候,這個鎖碰巧已經被一個讀操作持有,那么這個讀操作的解鎖將會失效(因為時間戳已經失效)。這個時候應用程序需要從頭再來,也許要使用悲觀模式的鎖(時間戳鎖也有實現)。你需要自己搞定這一切,并且一個時間戳只能解鎖它對應的鎖——這一點必須非常小心。

下面我們來看一下這種鎖的實例——

  1. long stamp = lock.tryOptimisticRead(); // 非阻塞路徑——超級快  
  2. work(); // 我們希望不要有寫操作在這時發生  
  3. if (lock.validate(stamp)){  
  4. //成功!沒有寫操作干擾   
  5. }  
  6. else {  
  7. //肯定同時有另外一個線程獲得了寫操作鎖,改變了時間戳  
  8. //懶漢說——我們切換到開銷更大的鎖吧  
  9.   
  10. stamp = lock.readLock(); //這是傳統的讀操作鎖,會阻塞  
  11. try {  
  12. //現在不可能有寫操作發生了  
  13. work();  
  14.   
  15. }  
  16. finally {  
  17. lock.unlock(stamp); // 使用對應的時間戳解鎖  
  18. }  
  19. }  

并發加法器

Java 8另一個出色的功能是并發“加法器”,它對大規模運行的代碼尤其有意義。一種最基本的并發模式就是對一個計數器的讀寫。就其本身而言,現今處理這個問題有很多方法,但是沒有一種能比Java 8提供的方法高效或優雅。

到目前為止,這個問題是用原子類(Atomics)來解決的,它直接利用了CPU的“比較并交換”指令(CAS)來測試并設置計數器的值。問題在于當一條CAS指令因為競爭而失敗的時候,AtomicInteger類會死等,在無限循環中不斷嘗試CAS指令,直到成功為止。在發生競爭概率很高的環境中,這種實現被證明是非常慢的。

來看Java 8的LongAdder。這一系列類為大量并行讀寫數值的代碼提供了方便的解決辦法。使用超級簡單。只要初始化一個LongAdder對象并使用它的add()和intValue()方法來累加和采樣計數器。

這和舊的Atomic類的區別在于,當CAS指令因為競爭而失敗時,Adder不會一直占著CPU,而是為當前線程分配一個內部cell對象來存儲計數器的增量。然后這個值和其他待處理的cell對象一起被加到intValue()的結果上。這減少了反復使用CAS指令或阻塞其他線程的可能性。

如果你問你自己,什么時候應該用并發加法器而不是原子類來管理計數器?簡單的答案就是——一直這么做。

并行排序

正像并發加法器能加速計數一樣,Java 8還實現了一種簡潔的方法來加速排序。這個秘訣很簡單。你不再這么做:

  1. Array.sort(myArray); 

而是這么做:

  1. Arrays.parallelSort(myArray); 

這會自動把目標數組分割成幾個部分,這些部分會被放到獨立的CPU核上去運行,再把結果合并起來。這里需要注意的是,在一個大量使用多線程的環境中,比如一個繁忙的Web容器,這種方法的好處就會減弱(降低90%以上),因為越來越多的CPU上下文切換增加了開銷。

切換到新的日期接口

Java 8引入了全新的date-time接口。當前接口的大多數方法都已被標記為deprecated,你就知道是時候推出新接口了。新的日期接口為Java核心庫帶來了易用性和準確性,而以前只能用Joda time才能達到這樣的效果(譯者注:Joda time是一個第三方的日期庫,比Java自帶的庫更友好更易于管理)。

跟任何新接口一樣,好消息是接口變得更優雅更強大。但不幸的是還有大量的代碼在使用舊接口,這個短時間內不會有改變。

為了銜接新舊接口,歷史悠久的Date類新增了toInstant()方法,用于把Date轉換成新的表示形式。當你既要享受新接口帶來的好處,又要兼顧那些只接受舊的日期表示形式的接口時,這個方法會顯得尤其高效。

控制操作系統進程

想在你的代碼里啟動一個操作系統進程,通過JNI調用就能完成——但這個東西總令人一知半解,你很有可能得到一個意想不到的結果,并且一路伴隨著一些很糟糕的異常。

即便如此,這是無法避免的事情。但進程還有一個討厭的特性就是——它們搞不好就會變成僵尸進程。目前從Java中運行進程帶來的問題是,進程一旦啟動就很難去控制它。

為了幫我們解決這個問題,Java 8在Process類中引入了三個新的方法

  • destroyForcibly——結束一個進程,成功率比以前高很多。
  • isAlive——查詢你啟動的進程是否還活著。
  • 重載了waitFor(),你現在可以指定等待進程結束的時間了。進程成功退出后這個接口會返回,超時的話也會返回,因為你有可能要手動終止它。

這里有兩個關于如何使用這些新方法的好例子——如果進程沒有在規定時間內退出,終止它并繼續往前走。

  1. if (process.wait(MY_TIMEOUT, TimeUnit.MILLISECONDS)){ 
  2. //成功  
  3. }else { 
  4.     process.destroyForcibly(); 

在你的代碼結束前,確保所有的進程都已退出。僵尸進程會逐漸耗盡系統資源。

  1. for (Process p : processes) { 
  2. if (p.isAlive()) { 
  3. p.destroyForcibly(); 

精確的數字運算

數字溢出會導致一些討厭的bug,因為它本質上不會出錯。在一些系統中,整型值不停地增長(比如計數器),溢出的問題就尤為嚴重。在這些案例里面,產品在演進階段運行得很好,甚至商用后的很長時間內也沒問題,但最終會出奇怪的故障,因為運算開始溢出,產生了完全無法預料的值。

為了解決這個問題,Java 8為Math類添加了幾個新的“精確型”方法,以便保護重要的代碼不受溢出的影響,它的做法是當運算超過它的精度范圍的時候,拋出一個未檢查的ArithmeticException異常。

  1. int safeC = Math.multiplyExact(bigA, bigB);  
  2. // 如果結果超出+-2^31,就會拋出ArithmeticException異常 

不好的地方就是你必須自己找出可能產生溢出的代碼。無論如何,沒有什么自動的解決方案。但我覺得有這些接口總比沒有好。

安全的隨機數發生器

在過去幾年中Java一直因為安全漏洞而飽受詬病。無論是否合理,Java已經做了大量工作來加強虛擬機和框架層,使之免受攻擊。如果隨機數來源于隨機性不高的種子,那么那些用隨機數來產生密鑰或者散列敏感信息的系統就更易受攻擊。

到目前為止,隨機數發生算法由開發人員來決定。但問題是,如果你想要的算法依賴于特定的硬件、操作系統、虛擬機,那你就不一定能實現它。這種情況下,應用程序傾向于使用更弱的默認發生器,這就使他們暴露在更大的風險下了。

Java 8添加了一個新的方法叫SecureRandom.getInstanceStrong(),它的目標是讓虛擬機為你選擇一個安全的隨機數發生器。如果你的代碼無法完全掌控操作系統、硬件、虛擬機(如果你的程序部署到云或者PaaS上,這是很常見的),我建議你認真考慮一下使用這個接口。

可選引用

空指針就像“踢到腳趾”一樣——從你學會走路開始就伴隨著你,無論現在你有多聰明——你還是會犯這個錯。為了幫助解決這個老問題,Java 8引入了一個新模板叫Optional<T>。

這個模板是從Scala和Hashkell借鑒來的,用于明確聲明傳給函數或函數返回的引用有可能是空的。有了它,過度依賴舊文檔或者看過的代碼經常變動的人,就不需要去猜測某個引用是否可能為空。

  1. Optional<User> tryFindUser(int userID) { 

  1. void processUser(User user, Optional<Cart> shoppingCart) { 

Optional模板有一套函數,使得采樣它更方便,比如isPresent()用來檢查這個值是不是非空,或者ifPresent()你可以傳遞一個Lambda函數過去,如果isPresent()返回true,這個Lambda函數就會被執行。不好的地方就跟Java 8的新日期接口一樣,等這種模式逐漸流行,滲透到我們使用的庫中和日常設計中,需要時間和工作量。

  1. value.ifPresent(System.out::print); 

[[256396]] 

 

責任編輯:龐桂玉 來源: 今日頭條
相關推薦

2011-03-09 09:26:38

2013-03-19 11:06:12

Windows 8微軟

2022-07-25 15:21:50

Java編程語言開發

2023-09-23 08:17:51

Java 17開發

2011-02-25 10:00:04

Windows 8

2014-07-15 11:25:18

2020-03-02 14:55:02

JavaBigDecimalAPI

2022-10-30 16:27:38

Java移動應用程序開發

2022-10-10 11:51:51

Java應用程序框架

2012-04-10 10:11:41

回顧Windows 8

2014-06-17 09:51:57

Docker

2023-02-24 14:46:32

Java線程池編程

2009-12-03 17:18:19

軟件路由器功能

2022-08-01 08:37:45

Java池化緩存

2016-12-26 11:00:57

Java開發者工具

2010-09-02 16:14:20

CSS布局

2019-10-18 15:16:10

Redis數據庫并發

2022-12-08 08:29:58

特征云計算操作系統

2017-01-05 09:59:45

2012-10-29 11:01:17

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久91| 红色av社区| 精品熟人一区二区三区四区 | 成人欧美一区二区三区视频xxx | 天天看天天操 | 成人精品一区二区户外勾搭野战 | 免费人成在线观看网站 | 玖玖综合在线 | 久久久久久国产 | 人人九九精| 亚洲欧洲精品在线 | 欧美一区二区三区在线观看 | 亚洲一区二区三区四区五区中文 | 日韩av免费在线电影 | 天天色图| 亚洲视频一区在线 | 精品亚洲一区二区 | av手机免费在线观看 | 欧美一级免费看 | www.久久影视| av网站在线免费观看 | 日韩欧美中文字幕在线观看 | 97视频久久 | 国产有码 | 欧美综合一区二区 | 成人精品在线视频 | 精品一区二区观看 | 九九导航 | 欧美激情欧美激情在线五月 | 亚洲精品久久区二区三区蜜桃臀 | 97伦理| 91中文在线观看 | 亚洲欧洲日韩精品 中文字幕 | 久久久成人动漫 | 99爱视频| 久久com | 欧美一区二区三区一在线观看 | 国产福利视频 | 99re视频在线观看 | 一级免费视频 | 久久久精 |