摘要:的方法,的默認實現會判斷是否是類型注意自動拆箱,自動裝箱問題。適應自旋鎖鎖競爭是下的,會經過用戶態到內核態的切換,是比較花時間的。在中引入了自適應的自旋鎖,說明自旋的時間不固定,要不要自旋變得越來越聰明。
前言
只有光頭才能變強
之前在刷博客的時候,發現一些寫得比較好的博客都會默默收藏起來。最近在查閱補漏,有的知識點比較重要的,但是在之前的博客中還沒有寫到,于是趁著閑整理一下。
文本的知識點:
Integer常量池
TCP拆包粘包
select、poll、epoll簡單區別
jdk1.6以后對Synchronize鎖優化
Java內存模型
本文力求簡單講清每個知識點,希望大家看完能有所收獲
一、神奇的Integer前陣子在群上看有人在討論關于Integer的true或者false問題,我本以為我已經懂了這方面的知識點了。但還是做錯了,后來去請教了一下朋友。朋友又給我發了另一張圖:
后來發現這是出自《深入理解Java虛擬機——JVM高級特性與最佳實踐(第2版)》中的10.3.2小節中~
public class Main_1 { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L; System.out.println(c == d); System.out.println(e == f); System.out.println(c == (a + b)); System.out.println(c.equals(a + b)); System.out.println(g == (a + b)); System.out.println(g.equals(a + b)); System.out.println(g.equals(a + h)); } }
你們可以先思考一下再往下翻看答案,看看能不能做對。
1.1解題思路在解這道題之前,相信很多人都已經知道了,在Java中會有一個Integer緩存池,緩存的大小是:-128~127
答案是:
true
false
true
true
true
false
true
簡單解釋一下:
使用==的情況:
如果比較Integer變量,默認比較的是地址值。
Java的Integer維護了從-128~127的緩存池
如果比較的某一邊有操作表達式(例如a+b),那么比較的是具體數值
使用equals()的情況:
無論是Integer還是Long中的equals()默認比較的是數值。
Long的equals()方法,JDK的默認實現:會判斷是否是Long類型
注意自動拆箱,自動裝箱問題。
反編譯一下看看:
import java.io.PrintStream; public class Main_1 { public static void main(String[] paramArrayOfString) { Integer localInteger1 = Integer.valueOf(1); Integer localInteger2 = Integer.valueOf(2); Integer localInteger3 = Integer.valueOf(3); Integer localInteger4 = Integer.valueOf(3); Integer localInteger5 = Integer.valueOf(321); Integer localInteger6 = Integer.valueOf(321); Long localLong = Long.valueOf(3L); // 緩存池 System.out.println(localInteger3 == localInteger4); // 超出緩存池范圍 System.out.println(localInteger5 == localInteger6); // 存在a+b數值表達式,比較的是數值 System.out.println(localInteger3.intValue() == localInteger1.intValue() + localInteger2.intValue()); // equals比較的是數值 System.out.println(localInteger3.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue()))); // 存在a+b數值表達式,比較的是數值 System.out.println(localLong.longValue() == localInteger1.intValue() + localInteger2.intValue()); // Long的equals()先判斷傳遞進來的是不是Long類型,而a+b自動裝箱的是Integer類型 System.out.println(localLong.equals(Integer.valueOf(localInteger1.intValue() + localInteger2.intValue()))); // ... 最后一句在這里漏掉了,大家應該可以推斷出來 } }
我使用的反編譯工具是jd-gui,如果還沒有試過反編譯的同學可以下載來玩玩:
https://github.com/java-decompiler/jd-gui/releases
二、Synchronize鎖優化手段有哪些多線程文章回顧:
ThreadLocal就是這么簡單
多線程三分鐘就可以入個門了!
Thread源碼剖析
多線程基礎必要知識點!看了學習多線程事半功倍
Java鎖機制了解一下
AQS簡簡單單過一遍
Lock鎖子類了解一下
線程池你真不來了解一下嗎?
多線程之死鎖就是這么簡單
Java多線程打輔助的三個小伙子
之前在寫多線程文章的時候,簡單說了一下synchronized鎖在jdk1.6以后會有各種的優化:適應自旋鎖,鎖消除,鎖粗化,輕量級鎖,偏向鎖。
本以為這些優化是非常難以理解的東西,其實不然~~~簡單了解一下還是很好理解的。
2.1適應自旋鎖鎖競爭是kernal mode下的,會經過user mode(用戶態)到kernal mode(內核態) 的切換,是比較花時間的。
自旋鎖出現的原因是人們發現大多數時候鎖的占用只會持續很短的時間,甚至低于切換到kernal mode所花的時間,所以在進入kernal mode前讓線程等待有限的時間,如果在此時間內能夠獲取到鎖就避免了很多無謂的時間,若不能則再進入kernal mode競爭鎖。
在JDK 1.6中引入了自適應的自旋鎖,說明自旋的時間不固定,要不要自旋變得越來越聰明。
自旋鎖在JDK1.4.2中就已經引入,只不過默認是關閉的,可以使用-XX:+UseSpinning參數來開啟,在JDK1.6中就已經改為默認開啟了。
參考資料:
自旋鎖和使線程休眠的非自旋鎖各有什么適用場景?https://www.zhihu.com/question/38857029/answer/78480263
2.2鎖消除如果JVM明顯檢測到某段代碼是線程安全的(言外之意:無鎖也是安全的),JVM會安全地原有的鎖消除掉!
比如說:
public void vectorTest(){ Vectorvector = new Vector (); for(int i = 0 ; i < 10 ; i++){ vector.add(i + ""); } System.out.println(vector); }
Vector是默認加鎖的,但JVM如果發現vector變量僅僅在vectorTest()方法中使用,那該vector是線程安全的。JVM會把vector內部加的鎖去除,這個優化就叫做:鎖消除。
2.3鎖粗化默認情況下,總是推薦將同步塊的作用范圍限制得盡量小。
但是如果一系列的連續操作都對同一個對象反復加鎖和解鎖,甚至加鎖操作是出現在循環體中的,頻繁地進行互斥同步操作也會導致不必要的性能損耗。
JVM會將加鎖的范圍擴展(粗化),這就叫做鎖粗化。
2.4輕量級鎖輕量級鎖能提升程序同步性能的依據是“對于絕大部分的鎖,在整個同步周期內都是不存在競爭的”,這是一個經驗數據。
如果沒有競爭,輕量級鎖使用CAS操作避免了使用互斥量的開銷
但如果存在鎖競爭,除了互斥量的開銷外,還額外發生了CAS操作,因此在有競爭的情況下,輕量級鎖會比傳統的重量級鎖更慢。
簡單來說:如果發現同步周期內都是不存在競爭,JVM會使用CAS操作來替代操作系統互斥量。這個優化就被叫做輕量級鎖。
2.5偏向鎖偏向鎖就是在無競爭的情況下把整個同步都消除掉,連CAS操作都不做了!
偏向鎖可以提高帶有同步但無競爭的程序性能。它同樣是一個帶有效益權衡(Trade Off)性質的優化,也就是說,它并不一定總是對程序運行有利,如果程序中大多數的鎖總是被多個不同的線程訪問,那偏向模式就是多余的。在具體問題具體分析的前提下,有時候使用參數-XX:-UseBiasedLocking來禁止偏向鎖優化反而可以提升性能。2.6簡單總結各種鎖優化
自適應偏向鎖:自旋時間不固定
鎖消除:如果發現代碼是線程安全的,將鎖去掉
鎖粗化:加鎖范圍過小(重復加鎖),將加鎖的范圍擴展
輕量級鎖:在無競爭的情況下使用CAS操作去消除同步使用的互斥量
偏向鎖:在無競爭環境下,把整個同步都消除,CAS也不做。
參考資料:
https://blog.csdn.net/chenssy/article/details/54883355
三、TCP粘包,拆包這是在看wangjingxin大佬面經的時候看到的面試題,之前對TCP粘包,拆包沒什么概念,于是就簡單去了解一下。
3.1什么是拆包粘包?為什么會出現?在進行Java NIO學習時,可能會發現:如果客戶端連續不斷的向服務端發送數據包時,服務端接收的數據會出現兩個數據包粘在一起的情況。
TCP的首部格式:
TCP是基于字節流的,雖然應用層和TCP傳輸層之間的數據交互是大小不等的數據塊,但是TCP把這些數據塊僅僅看成一連串無結構的字節流,沒有邊界;
從TCP的幀結構也可以看出,在TCP的首部沒有表示數據長度的字段
基于上面兩點,在使用TCP傳輸數據時,才有粘包或者拆包現象發生的可能。
一個數據包中包含了發送端發送的兩個數據包的信息,這種現象即為粘包
接收端收到了兩個數據包,但是這兩個數據包要么是不完整的,要么就是多出來一塊,這種情況即發生了拆包和粘包
拆包和粘包的問題導致接收端在處理的時候會非常困難(因為無法區分一個完整的數據包)
3.2解決拆包和粘包分包機制一般有兩個通用的解決方法:
1,特殊字符控制
2,在包頭首都添加數據包的長度
如果使用netty的話,就有專門的編碼器和解碼器解決拆包和粘包問題了。
tips:UDP沒有粘包問題,但是有丟包和亂序。不完整的包是不會有的,收到的都是完全正確的包。傳送的數據單位協議是UDP報文或用戶數據報,發送的時候既不合并,也不拆分。
參考資料
https://blog.csdn.net/scythe666/article/details/51996268--->TCP粘包,拆包及解決方法
http://www.ideawu.net/blog/archives/993.html--->關于TCP粘包和拆包的終極解答
四、select、poll、epoll簡單區別NIO回顧:
JDK10都發布了,nio你了解多少?
在Linux下它是這樣子實現I/O復用模型的:
調用select/poll/epoll其中一個函數,傳入多個文件描述符,如果有一個文件描述符就緒,則返回,否則阻塞直到超時。
這幾個函數是有些區別的,可能有的面試官會問到這三個函數究竟有什么區別:
區別如下圖:
兩句話總結:
select和poll都需要輪詢每個文件描述符,epoll基于事件驅動,不用輪詢
select和poll每次都需要拷貝文件描述符,epoll不用
select最大連接數受限,epoll和poll最大連接數不受限
tips:epoll在內核中的實現,用紅黑樹管理事件塊4.1通俗例子
現在3y在公司里邊實習,寫完的代碼需要給測試測一遍。
select/poll情況:
開發在寫代碼,此時測試挨個問所有開發者,你寫好程序了沒有?要測試嗎?
epoll情況:
開發寫完代碼了,告訴測試:“我寫好代碼了,你去測測,功能是XXX”。于是測試高高興興去找bug了。
其他通俗描述[1]:
一個酒吧服務員(一個線程),前面趴了一群醉漢,突然一個吼一聲“倒酒”(事件),你小跑過去給他倒一杯,然后隨他去吧,突然又一個要倒酒,你又過去倒上,就這樣一個服務員服務好多人,有時沒人喝酒,服務員處于空閑狀態,可以干點別的玩玩手機。至于epoll與select,poll的區別在于后兩者的場景中醉漢不說話,你要挨個問要不要酒,沒時間玩手機了。io多路復用大概就是指這幾個醉漢共用一個服務員。
來源:
https://www.zhihu.com/question/32163005/answer/55687802
其他通俗描述[2]:
簡單舉個例子(可能也不是很形象)select/poll飯店服務員(內核)告訴飯店老板(用戶程序):”現在有客人結賬“但是這個服務員沒人明確告訴老板,哪幾桌的客人結帳。老板得自兒一個一個桌子去問:請問是你要結帳?epoll飯店服務員(內核)告訴飯店老板(用戶程序):”1,2,5號客人結賬“老板就可以直接去1,2,5號桌收錢了
來源:
https://www.zhihu.com/question/21233763/answer/23837166
深入了解參考資料:
https://www.cnblogs.com/Anker/p/3265058.html--->select、poll、epoll之間的區別總結[整理]
五、Java內存模型JVM博文回顧:
JVM如何從入門到放棄的?
之前在寫JVM的時候,還一度把JVM內存結構與Java內存模型給搞混了~~~還好有熱心的網友給我指出來。
JVM內存結構:
Java內存模型:
操作變量時的規則:
Java內存模型規定了所有的變量都存儲在主內存
線程的工作內存中保存了被該線程使用到的變量的主內存副本拷貝
線程對變量的所有操作(讀取、賦值等)都必須在工作內存中進行,而不能直接讀寫主內存中的變量
從工作內存同步回主內存實現是通過以下的8種操作來完成:
lock(鎖定):作用于主內存的變量,把一個變量標識為一條線程獨占狀態。
unlock(解鎖):作用于主內存變量,把一個處于鎖定狀態的變量釋放出來,釋放后的變量才可以被其他線程鎖定。
read(讀取):作用于主內存變量,把一個變量值從主內存傳輸到線程的工作內存中,以便隨后的load動作使用
load(載入):作用于工作內存的變量,它把read操作從主內存中得到的變量值放入工作內存的變量副本中。
use(使用):作用于工作內存的變量,把工作內存中的一個變量值傳遞給執行引擎,每當虛擬機遇到一個需要使用變量的值的字節碼指令時將會執行這個操作。
assign(賦值):作用于工作內存的變量,它把一個從執行引擎接收到的值賦值給工作內存的變量,每當虛擬機遇到一個給變量賦值的字節碼指令時執行這個操作。
store(存儲):作用于工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨后的write的操作。
write(寫入):作用于主內存的變量,它把store操作從工作內存中一個變量的值傳送到主內存的變量中。
Java內存模型是圍繞著在并發過程中如何處理原子性、可見性和有序性這3個特征來建立的
保證原子性的操作:
read、load、assign、use、store和write
synchronized鎖
保證有序性(重排序導致無序)的操作:
volatile
synchronized鎖
保證可見性:
volatile
synchronized鎖
final
在上面也說了,有序性可以通過volatile和synchronized鎖來保證,但我們一般寫程序的時候不會總是關注代碼的有序性的。其實,我們Java內部中有一個原則,叫做先行發生原則(happens-before)
“先行發生”(happens-before)原則可以通過:幾條規則一攬子地解決并發環境下兩個操作之間是否可能存在沖突的所有問題
有了這些規則,并且我們的操作是在這些規則定義的范圍之內。我們就可以確保,A操作肯定比B操作先發生(不會出現重排序的問題)
“先行發生”(happens-before)原則有下面這么幾條:
程序次序規則(Program Order Rule):在一個線程內,按照程序代碼順序,書寫在前面的操作先行發生于書寫在后面的操作。準確地說,應該是控制流順序而不是程序代碼順序,因為要考慮分支、循環等結構。
管程鎖定規則(Monitor Lock Rule):一個unlock操作先行發生于后面對同一個鎖的lock操作。這里必須強調的是同一個鎖,而“后面”是指時間上的先后順序。
volatile變量規則(Volatile Variable Rule):對一個volatile變量的寫操作先行發生于后面對這個變量的讀操作,這里的“后面”同樣是指時間上的先后順序。線程啟動規則(Thread Start Rule):Thread對象的start()方法先行發生于此線程的每一個動作。
線程終止規則(Thread Termination Rule):線程中的所有操作都先行發生于對此線程的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。
線程中斷規則(Thread Interruption Rule):對線程interrupt()方法的調用先行發生于被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interrupted()方法檢測到是否有中斷發生。
對象終結規則(Finalizer Rule):一個對象的初始化完成(構造函數執行結束)先行發生于它的finalize()方法的開始。
傳遞性(Transitivity):如果操作A先行發生于操作B,操作B先行發生于操作C,那就可以得出操作A先行發生于操作C的結論。
參考資料:
【深入理解JVM】:Java內存模型JMM:https://blog.csdn.net/u011080472/article/details/51337422
Java的內存模型(1):https://www.cnblogs.com/jian0110/p/9351281.html
六、最后本文簡單整理了一下在學習中做的筆記,還有在網上遇到一些比較重要的知識點(面試題)~希望大家看完能有所收益。
參考資料:
《深入理解Java虛擬機——JVM高級特性與最佳實踐(第2版)》
如果大家有更好的理解方式或者文章有錯誤的地方還請大家不吝在評論區留言,大家互相學習交流~~~
如果想看更多的原創技術文章,歡迎大家關注我的微信公眾號:Java3y。Java技術群討論:742919422。公眾號還有海量的視頻資源哦,關注即可免費領取。
可能感興趣的鏈接:
文章的目錄導航(微信公眾號端):https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
文章的目錄導航(PC端):http://www.zhongfucheng.bitcron.com/post/shou-ji/pcduan-wen-zhang-dao-hang
海量精美腦圖:http://www.zhongfucheng.bitcron.com/post/shou-ji/nao-tu-da-quan
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76597.html
摘要:這幾道面試題都不懂,肯定與你擦肩而過如何解決緩存雪崩如何解決緩存穿透如何保證緩存與數據庫雙寫時一致的問題一緩存雪崩什么是緩存雪崩回顧一下我們為什么要用緩存現在有個問題,如果我們的緩存掛掉了,這意味著我們的全部請求都跑去數據庫了。 這幾道Redis面試題都不懂,offer肯定與你擦肩而過 showImg(https://segmentfault.com/img/bVbuYpH?w=640...
摘要:這幾道面試題都不懂,肯定與你擦肩而過如何解決緩存雪崩如何解決緩存穿透如何保證緩存與數據庫雙寫時一致的問題一緩存雪崩什么是緩存雪崩回顧一下我們為什么要用緩存現在有個問題,如果我們的緩存掛掉了,這意味著我們的全部請求都跑去數據庫了。 這幾道Redis面試題都不懂,offer肯定與你擦肩而過 showImg(https://segmentfault.com/img/bVbuYpH?w=640...
摘要:第一種方法常規方法。如果不存在公共前綴,返回空字符串。注意假設字符串的長度不會超過。說明本題中,我們將空字符串定義為有效的回文串。示例輸入輸出一個可能的最長回文子序列為。數值為或者字符串不是一個合法的數值則返回。 說明 本文作者:wwwxmu 原文地址:https://www.weiweiblog.cn/13s... 作者的博客站點:https://www.weiweiblog.c...
摘要:面試后面試后及時總結,有可能下一個面試官會問你同樣的問題。同時面試官也對我的未來技術發展提出了很多建議。總的來說,四面的氛圍并沒有想象得那么嚴肅,面試官也說面試得很愉快。 ...
閱讀 1609·2021-09-23 11:31
閱讀 924·2021-09-23 11:22
閱讀 1347·2021-09-22 15:41
閱讀 4076·2021-09-03 10:28
閱讀 2911·2019-08-30 15:55
閱讀 3545·2019-08-30 15:55
閱讀 1954·2019-08-30 15:44
閱讀 2717·2019-08-30 13:50