1.說(shuō)一下面向?qū)ο蟮娜筇卣魅已悖惺裁刺攸c(diǎn)轧邪?
繼承闲勺、封裝菜循、多態(tài)
繼承:繼承就是子類通過(guò)extends繼承父類的方法癌幕,是發(fā)生在類與類之間的,可以復(fù)用父類的方法胶逢,同時(shí)也可以在這個(gè)基礎(chǔ)上對(duì)方法進(jìn)行重寫(xiě)來(lái)滿足我們的業(yè)務(wù)需求初坠,需要注意的是碟刺,子類不能繼承父類的構(gòu)造方法半沽。
封裝:封裝就是通過(guò)private把對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié)給隱藏起來(lái),同時(shí)給外界提供一個(gè)公共的入口來(lái)進(jìn)行訪問(wèn)幔托;可以提高信息的安全和降低代碼的耦合性重挑。
多態(tài):多態(tài)指的是我們平時(shí)定義的引用變量所指向的具體類型在編程時(shí)是不確定的谬哀,是在我們程序運(yùn)行的階段才能知道具體指向了哪一個(gè)實(shí)例對(duì)象谦屑;多態(tài)可以降低耦合性氢橙,使代碼更加靈活多變悍手;多態(tài)存在有三個(gè)必要條件:繼承坦康、重寫(xiě)、父類的對(duì)象指向子類的引用筛璧。
補(bǔ)充:
多態(tài)的實(shí)現(xiàn)方式隧哮?
1.方法重寫(xiě)或者重載2.接口實(shí)現(xiàn)3.抽象類和抽象方法
重寫(xiě)和重載的區(qū)別?
重寫(xiě)發(fā)生在子類和父類之間,是當(dāng)父類的方法不能滿足需求子類需求的時(shí)候來(lái)重寫(xiě)方法承二。重載發(fā)生在一個(gè)類中亥鸠,方法名相同负蚊,形參列表不同家妆。
構(gòu)造器是否可以被重寫(xiě)蛹找?
構(gòu)造不能被重寫(xiě)庸疾,但是可以被重載
重載的方法是否可以根據(jù)返回值類型進(jìn)行區(qū)分届慈?
不可以,因?yàn)檎{(diào)用的時(shí)候不能指定類型信息串绩,編譯器不知道你調(diào)用的是哪個(gè)方法礁凡。
2.String為什么要用final修飾?
首先我們知道被final修飾的類被稱為最終類窟蓝,是不能被重寫(xiě)的运挫,而String作為一個(gè)我們的常用類,在設(shè)計(jì)的時(shí)候底層調(diào)動(dòng)了許多我們計(jì)算機(jī)本地的一些方法去進(jìn)行操作碾牌,如果我們不用final修飾舶吗,就可以重寫(xiě)這些方法,那么在安全方面會(huì)存在很大的問(wèn)題踊赠;其次被final修飾后也是不可變的筐带,所以在創(chuàng)建的時(shí)候,他的hashcode就被緩存了帖鸦,字符串的處理速度比較快作儿,所以我們?cè)趍ap中也經(jīng)常使用字符串作為鍵。
String的常用方法娶吞?
我們?cè)谄綍r(shí)工作中常用的方法的話大概有:字符串比較equal、大小寫(xiě)轉(zhuǎn)換touppercase/tolowercase材部、去除空白tirim、分割split浸颓、替換replace等等棵磷。
==和equals的區(qū)別
== 對(duì)于基本數(shù)據(jù)類型比較的是值,對(duì)于引用數(shù)據(jù)類型比較的是地址值
equals重寫(xiě)后比較的是引用類型對(duì)象的地址值
為什么重寫(xiě)equal后算吩,hashcode也必須重寫(xiě)?
hashcode在具有哈希機(jī)制的集合中非常重要压昼,比如說(shuō)我們常用的hashset或者h(yuǎn)ashmap,在向hashset中添加對(duì)象時(shí)窍霞,首先會(huì)計(jì)算hashcode值來(lái)確定對(duì)象的儲(chǔ)存位置,當(dāng)這個(gè)位置沒(méi)有對(duì)象時(shí)傲绣,會(huì)直接添加到這個(gè)位置,如果這個(gè)位置有對(duì)象菠净,那么會(huì)判斷他們equals比較的結(jié)果毅往,如果還會(huì)相等派近,那么添加對(duì)象失敗攀唯,如果不同的話,會(huì)把對(duì)象添加到其他位置渴丸;所以侯嘀,假如我們不重寫(xiě)hashcode,那么就會(huì)導(dǎo)致每一個(gè)對(duì)象的hashcode值都一定不相等另凌,所以當(dāng)添加對(duì)象的時(shí)候都會(huì)成功戒幔,這樣的話會(huì)出現(xiàn)大量的重復(fù)key,在集合中key的值會(huì)唯一吠谢,所以我們重寫(xiě)了equals后必須重寫(xiě)hashcode;同時(shí)我們?cè)谔砑訉?duì)象的時(shí)候是先比較的hashcode的值诗茎,如果hashcode值不同工坊,他們一定不想等,可以在一定程度上提高集合的效率敢订。 (總結(jié):第一王污,在HashSet等集合中,不重寫(xiě)hashCode方法會(huì)導(dǎo)致其功能出現(xiàn)問(wèn)題枢析;第二玉掸,可以提高集合效率。)
String Stringbuilder StringBuffer的區(qū)別
技巧:是否可變醒叁,是否安全司浪,效率高低
他們都是用來(lái)操作字符串的類
String類有final修飾,是不可變的把沼,也是安全的啊易,我們每次對(duì)它進(jìn)行修改的時(shí)候都會(huì)重新創(chuàng)建一個(gè)新的對(duì)象,所以在我們需要經(jīng)常對(duì)字符串進(jìn)行操作的時(shí)候不適合用String類饮睬。
StringBuffer是可變的租谈,他們可以主要是通過(guò)調(diào)用append和insert方法對(duì)字符串進(jìn)行操作,同時(shí)它也被synconaized修飾捆愁,所以是線程安全的割去。適合在多線程的時(shí)候使用。
StringBuider基本和Buffer一致昼丑,區(qū)別是呻逆,它沒(méi)有synconaized修飾,所以是線程不安全的菩帝,但效率比Buffer高咖城,所以在不考慮線程安全的問(wèn)題時(shí)可以優(yōu)先選用StringBuilder.
3.說(shuō)一下java的四大權(quán)限修飾符有哪些
public 默認(rèn)不寫(xiě) protect private
public的話是對(duì)所有類都可以用
默認(rèn)不寫(xiě) 是默認(rèn)權(quán)限 對(duì)本類和同一個(gè)包中的類都可見(jiàn)
protect 是受保護(hù)的權(quán)限,只能是本類和它的子類可以使用(子類可以不同包)
private 私有的權(quán)限呼奢,只能在本類中使用宜雀。在項(xiàng)目中的話我們用的比較多的是pubic和private
4.static關(guān)鍵字的作用
技巧:修飾變量 + 修飾方法+ 修飾代碼塊
被static修飾的變量稱為靜態(tài)變量,在類初次加載的時(shí)候就會(huì)被加載握础,內(nèi)存中只有一個(gè)副本辐董,被所有對(duì)象共享,我們可以直接通過(guò)類名來(lái)直接訪問(wèn)禀综。
被static修飾的方法稱為靜態(tài)方法郎哭,也是在類初次加載的時(shí)候就會(huì)被加載他匪,我們可以直接通過(guò)類型.方法名的方式來(lái)訪問(wèn),但需要注意的是我們可以在非靜態(tài)方法中訪問(wèn)靜態(tài)方法卻不能在靜態(tài)方法中去訪問(wèn)非靜態(tài)方法(可能會(huì)問(wèn)原因夸研?)
被static修飾的代碼塊稱為靜態(tài)代碼塊,我們通常會(huì)把一些需要提前加載或者只需要進(jìn)行一次初始化操作的代碼放到靜態(tài)代碼塊中依鸥,這樣可以跟隨類加載的時(shí)候一起加載亥至,優(yōu)化程序的性能。
5.final關(guān)鍵字的作用
技巧:修飾變量+修飾方法+修飾類
final修飾變量 被修飾的變量不可以改變
final修飾方法 不能被重寫(xiě)
final修飾類 不能被重寫(xiě)
final finally finalize區(qū)別
final 可以修飾變量 方法 類
finally 一般是用在try catch代碼塊中贱迟,在處理異常的時(shí)候姐扮,放在finally中的代碼不管是否出現(xiàn)異常都會(huì)被執(zhí)行,一般用來(lái)存放關(guān)閉靜態(tài)資源的代碼
finalize 是obeject類中的一個(gè)方法衣吠,通常用在垃圾回收的時(shí)候茶敏,當(dāng)我們調(diào)用system.gc方法的時(shí)候,垃圾回收器回去調(diào)用finalize()方法回收垃圾缚俏。
6.this和supper的區(qū)別
技巧:this用于當(dāng)前類 supper指向父類
相同點(diǎn):
都必須放在構(gòu)造方法的第一行調(diào)用惊搏、否則會(huì)報(bào)錯(cuò);this和super都指向的是對(duì)象忧换,所以不能在static環(huán)境下使用
不同點(diǎn):
this:一般用來(lái)引用當(dāng)前類的變量恬惯、方法和構(gòu)造函數(shù),主要是在同一類的不同構(gòu)造函數(shù)中使用亚茬。
supper:用來(lái)引用父類的變量酪耳、方法和構(gòu)造函數(shù),主要是對(duì)父類構(gòu)造方法的調(diào)用刹缝,用在子類中碗暗。
7.抽象類和接口的區(qū)別
技巧:相同點(diǎn),不同點(diǎn)(定義梢夯,修飾符言疗,實(shí)現(xiàn),繼承厨疙,字段聲明洲守,構(gòu)造器)
相同點(diǎn):
都不可以被實(shí)例化,子類都必須重寫(xiě)父類的抽象方法
不同點(diǎn)
定義:抽象類用abstract 定義 接口用interface
修飾符:抽象類可以用public protect 默認(rèn)不寫(xiě)沾凄, 接口只能用public修飾
實(shí)現(xiàn):抽象是用extends繼承的方式 接口是用的impements實(shí)現(xiàn)的方式
繼承:?jiǎn)卫^承梗醇,多實(shí)現(xiàn)
字段聲明:抽象類字段聲明可以是任意的;接口的字段默認(rèn)是由static和final修飾撒蟀,可以用來(lái)定義全局常量
構(gòu)造器:抽象類有構(gòu)造器 接口沒(méi)有
8.jdk1.8提供了哪些新特性
1.lambda表達(dá)式:本質(zhì)就是一個(gè)匿名內(nèi)部類的簡(jiǎn)寫(xiě)
2.stream流:在新的stream包中針對(duì)集合的操作提供了并行和串行操作流
3.函數(shù)式接口:接口里面只有一個(gè)抽象方法
4.接口新增了默認(rèn)方法和靜態(tài)方法
5.新的日期API:相對(duì)于以前老的API叙谨,線程安全,有專門(mén)的時(shí)區(qū)處理
stream流常用API:
由于是針對(duì)集合的操作保屯,有遍歷foreach()手负,排序sorted()涤垫,去重distinct(),最大/最小max()/min()
9.臨時(shí)補(bǔ)充:(重點(diǎn))
SpringBoot的自動(dòng)配置原理竟终?
SpringBoot啟動(dòng)類上有一個(gè)重要的注解@SpringBootApplication,這是一個(gè)組合注解蝠猬,啟動(dòng)的時(shí)候,可以通過(guò)它里面的@EnableConfiguration注解去找到META-INF里面的所有自動(dòng)配置類统捶,并進(jìn)行加載榆芦,而這些配置類都是以AutoConfiguration結(jié)尾來(lái)命名的,這個(gè)配置類能夠通過(guò)以Properties結(jié)尾命名的類取得配置中的屬性喘鸟,當(dāng)我們使用run()方法啟動(dòng)的時(shí)候就可以通過(guò)@AutoConfigurationImportSelector注解去篩選加載匆绣,完成SpringBoot的自動(dòng)配置。
10.反射機(jī)制是什么什黑?
技巧:動(dòng)態(tài)獲取信息和動(dòng)態(tài)調(diào)用方法的功能
java的反射機(jī)制就是在運(yùn)行的狀態(tài)下崎淳,對(duì)于任意一個(gè)類,都可以獲得它的屬性和方法愕把,對(duì)于任意一個(gè)對(duì)象拣凹,都可以去調(diào)用他的屬性和方法,這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用方法的功能就是java的反射機(jī)制礼华。
優(yōu)點(diǎn):動(dòng)態(tài)加載類咐鹤,提高代碼的靈活度。
缺點(diǎn):性能比直接的java代碼要慢很多圣絮。(它里面的Method/invoke方法會(huì)對(duì)參數(shù)進(jìn)行封裝和解封的操作祈惶,同時(shí)也會(huì)對(duì)參數(shù)進(jìn)行一個(gè)校驗(yàn))
應(yīng)用場(chǎng)景:(這兩個(gè)回答的相關(guān)問(wèn)題需要去了解,防止面試官問(wèn)到)
1.java中的很多框架都用到了反射扮匠,比如spring中xml的配置
2.動(dòng)態(tài)代理設(shè)計(jì)模式也用到了反射機(jī)制
Java獲取Class對(duì)象的三種方式
public class Main{
public static void main(String[] args) throws ClassNotFoundException {
//方式1
Person p1 = new Person();
Class c1 = p1.getClass();
//方式2
Class c2 = Person.class;
//方式3可能會(huì)拋出ClassNotFoundException異常
Class c3 = Class.forName("com.company");
}
}
11.java的異常有哪些捧请?
java的異常有兩個(gè)重要的子類,error和exception棒搜,error是JVM本身的錯(cuò)誤疹蛉,所以我們關(guān)注的是Exception,exception又分為運(yùn)行時(shí)異常RuntimeException和非運(yùn)行時(shí)異常,我們比較常見(jiàn)的運(yùn)行時(shí)異常的話有
算數(shù)異常力麸,數(shù)組越界異常可款,空指針異常,類型轉(zhuǎn)換異常等等克蚂。
12.java容器相關(guān)面試題
Java 容器都有哪些闺鲸?
數(shù)組,String,以及java.util包下的list set map,list常用的是arrayList和linkedList,set常用的是hashset埃叭,map常用的是hashmap
list set map的區(qū)別摸恍?
首先他們?nèi)齻€(gè)都是接口,都不可以被實(shí)例化。
list和set都是collection接口下的子接口立镶,list是有序可重復(fù)的壁袄,set是無(wú)序不可重復(fù)的,map存放是key-value的鍵值對(duì)媚媒。
collection和colletions的區(qū)別嗜逻?
collection是一個(gè)集合接口,也是list和set的父接口。colletctions是一個(gè)包裝類缭召,也可以說(shuō)更像是一個(gè)工具類变泄,它里面提供了許多對(duì)集合進(jìn)行操作的靜態(tài)方法,比如排序sort恼琼,復(fù)制copy,反轉(zhuǎn),替換屏富,搜索等方法晴竞。
ArrayList 和 LinkedList 的區(qū)別是什么?
ArrayList和Linkedlist都是List的實(shí)現(xiàn)類狠半,同時(shí)也都是線程不安全的噩死。
ArrayList是基于我們數(shù)組實(shí)現(xiàn)的,而LinkedList是基于鏈表神年,所以我們?cè)谛枰M(jìn)行查詢的時(shí)候已维,更適合使用ArrayList,因?yàn)樗鼘?shí)現(xiàn)了RandomAccess接口已日,所以我們可以快速定位到某個(gè)具體的元素垛耳;在增刪的時(shí)候更適合我們的linkedList。這個(gè)跟數(shù)組和鏈表的結(jié)構(gòu)有關(guān)飘千,當(dāng)我們使用ArrayList進(jìn)行增刪時(shí)堂鲜,我們可能需要對(duì)數(shù)組進(jìn)行擴(kuò)容或者是復(fù)制的操作,這樣效率肯定慢护奈,而使用linkenList的話缔莲,由于是基于鏈表的,所以我們只用改變對(duì)應(yīng)元素的兩個(gè)節(jié)點(diǎn)的位置就可以完成操作霉旗,所以效率高痴奏。
ArrayList 和 Vector 的區(qū)別是什么?
技巧:安全厌秒,效率读拆,擴(kuò)容
ArrayList 和 Vector都是list的實(shí)現(xiàn)類,底層都是基于數(shù)組實(shí)現(xiàn)简僧。
ArrayList是線程不安全的建椰,Vector有Synchronized修飾,所以說(shuō)是線程安全的岛马。同時(shí)因?yàn)榧恿随i的原因棉姐,vector的效率相對(duì)于ArrayList也更低屠列。在需要擴(kuò)容的時(shí)候Arraylist是會(huì)擴(kuò)容百分之50,而Vecto擴(kuò)容會(huì)增加1倍伞矩。
HashMap 的實(shí)現(xiàn)原理?
HashMap是基于map實(shí)現(xiàn)的笛洛,以key-value的形式對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ),在jdk1.8以后乃坤,數(shù)據(jù)結(jié)構(gòu)從數(shù)組+鏈表形式升級(jí)為數(shù)組+鏈表+紅黑樹(shù)的形式苛让;當(dāng)我們使用put方法存入一個(gè)元素的時(shí)候,hashmap會(huì)調(diào)用key.hashcode方法計(jì)算hashcode值湿诊,根據(jù)hash值將value保存在bucket里面狱杰,當(dāng)hashcode的值相同的時(shí)候,會(huì)發(fā)生hash碰撞厅须,hashmap解決hash碰撞的方式是使用 使用鏈表和紅黑樹(shù)仿畸,當(dāng)沖突個(gè)數(shù)比較少的時(shí)候存到鏈表里面,沖突個(gè)數(shù)超過(guò)8個(gè)的時(shí)候會(huì)將鏈表轉(zhuǎn)換成紅黑樹(shù)(treeifyBin方法())朗和。
補(bǔ)充:如果兩個(gè)key的hashcode相同错沽,你如何獲取值對(duì)象
首先調(diào)用get方法根據(jù)key.hashcode的值找到bucket中這個(gè)對(duì)象位置,如果有兩個(gè)值對(duì)象眶拉,會(huì)對(duì)鏈表進(jìn)行遍歷千埃,然后找到值對(duì)象。
這時(shí)會(huì)如果問(wèn):你并沒(méi)有值對(duì)象去比較忆植,你是如何確定確定找到值對(duì)象的放可?
首先找到在bucket的位置之后,會(huì)調(diào)用key.equals方法去找到鏈表中正確的節(jié)點(diǎn)唱逢,最終找到想要的對(duì)象吴侦。
Java中的HashMap的初始容量和擴(kuò)容
hashmap是使用的懶加載的機(jī)制,在我們剛創(chuàng)建一個(gè)map對(duì)象的時(shí)候坞古,他的初始容量是為0的备韧,當(dāng)我們調(diào)用map的put方法去進(jìn)行添加操作的時(shí)候,這時(shí)put()方法里面才會(huì)調(diào)用resize()方法設(shè)置map的初始容量痪枫,默認(rèn)的是設(shè)置為16织堂,我們也可以自己指定容量。同時(shí)擴(kuò)容的時(shí)機(jī)和負(fù)載因子有關(guān)奶陈,默認(rèn)是0.75易阳,也就是說(shuō)當(dāng)我們map的容量達(dá)到12的時(shí)候,會(huì)進(jìn)行擴(kuò)容吃粒,每次擴(kuò)容的大小是2倍潦俺。
HashMap為什么會(huì)是2倍的形式進(jìn)行擴(kuò)容呢?
hashmap的初始容量都是2的n次方,我們擴(kuò)容后的容量也是2的n次方,因?yàn)檫@樣設(shè)計(jì)可以最大程度上減少hash碰撞事示,并且是通過(guò)位運(yùn)算的方式早像,效率也比較高。并且所以在map進(jìn)行擴(kuò)容的時(shí)候是以2倍的方式進(jìn)行擴(kuò)容的肖爵。
HashMap 和 Hashtable 有什么區(qū)別卢鹦?
HashMap 和 Hashtable 都是實(shí)現(xiàn)了map serializable 以及 可克隆 接口。
區(qū)別:
底層結(jié)構(gòu)不同:HashMap底層數(shù)據(jù)結(jié)構(gòu)1.8以前用的數(shù)組+鏈表的形式劝堪,1.8以后更新為數(shù)組+鏈表+紅黑樹(shù)冀自;HashTable底層數(shù)據(jù)結(jié)構(gòu)用的是數(shù)組+鏈表
初始容量不同:HashMap 初始容量是16,Hashtable 初始容量是11秒啦,負(fù)載因子都是0.75
添加鍵值對(duì)key-value的時(shí)候熬粗,使用的hash算法不同,HashMap 使用的是自定義的hash算法余境,hashTable使用的key.hashcode
HashMap允許key和value為null,HashTable不允許鍵或值為null
擴(kuò)容機(jī)制不同:HashMap擴(kuò)容的時(shí)候是擴(kuò)容2倍荐糜,而Hashtab擴(kuò)容的時(shí)候是2倍的基礎(chǔ)上+1
HashMap只支持iterator遍歷,HashTable支持itetator和enumeration遍歷
HashMap是線程不安全的葛超,Hashtable 是線程安全的。
JDK1.8前HashMap也是采用頭插法延塑,為什么1.8改為了尾插法绣张?
1.8以前,hashmap的數(shù)據(jù)結(jié)構(gòu)采用的是數(shù)組+鏈表的方式关带,使用頭插法容易造成鏈表成環(huán)的問(wèn)題侥涵,形成死鏈。
那為什么hashtable在1.8以后依然使用頭插法宋雏?
因?yàn)閔ashtable是線程安全的芜飘,不用擔(dān)心并發(fā)問(wèn)題,使用頭插法效率更高磨总。
HashTable和ConcurrentHashMap的區(qū)別?
HashMap是線程不安全的嗦明,當(dāng)出現(xiàn)多線程操作時(shí),會(huì)出現(xiàn)安全隱患蚪燕,我們可能會(huì)想到HashTable娶牌,是的,這個(gè)是線程安全的馆纳,但是HashTable用的是方法鎖诗良,把整個(gè)put方法都上鎖了,這就導(dǎo)致了效率很低鲁驶,如果把put方法比作是一個(gè)有很多房間的院子鉴裹,那么HathTable的鎖就相當(dāng)于是把院子的大門(mén)鎖上了。而ConcurrentHashMap是用的塊鎖,相當(dāng)于是把院子里的有安全隱患的房間鎖上了径荔,這樣一來(lái)督禽,就不會(huì)讓去其他房間辦事的人等待了。
詳細(xì)原理參考:https://blog.csdn.net/qq_45036591/article/details/105470901
Comparable和Comparator區(qū)別猖凛?
Comparable和 Comparator都是java.util包下的兩個(gè)接口赂蠢,都是用來(lái)做比較的。
Comparable接口用于進(jìn)行自然排序辨泳,而Comparator接口用于自定義排序虱岂,自定義排序更加靈活方便而常用。
comparable在設(shè)計(jì)上不推薦使用菠红,它對(duì)程序本身具有入侵性第岖。
Iterator 怎么使用?有什么特點(diǎn)试溯?
它可以用來(lái)遍歷任何collection的接口蔑滓,在使用的時(shí)候可以使用hasnext()方法進(jìn)行循環(huán),使用next()方法進(jìn)行取值遇绞。它的特點(diǎn)就是更加安全键袱,因?yàn)樗牡魇褂玫氖莊ast-fail機(jī)制,在當(dāng)前遍歷集合的元素被更改的時(shí)候就會(huì)拋出 并發(fā)修改異常(ConcurrentModificationExceptio)摹闽。
13.線程常見(jiàn)面試題匯總
一蹄咖、線程基礎(chǔ)
什么是線程?什么是進(jìn)程付鹿?他們之間有什么區(qū)別澜汤?線程的好處和壞處?
進(jìn)程是操作系統(tǒng)中分配資源的最小單元舵匾,而線程就是操作系統(tǒng)中調(diào)度資源的最小單元俊抵;通俗理解的話,我們電腦上啟動(dòng)的一個(gè)word應(yīng)用程序就是一個(gè)線程坐梯,word程序里面我們可以同時(shí)打字和實(shí)現(xiàn)自動(dòng)保存徽诲,這個(gè)就是線程完成的。
線程的好處就是可以解決部分同時(shí)運(yùn)行的問(wèn)題吵血,比如我們可以一邊聽(tīng)歌馏段,一邊打游戲;壞處的話就是我們開(kāi)啟的線程過(guò)多践瓷,每個(gè)線程都會(huì)占用資源院喜,會(huì)造成我們的電腦卡頓。
Java中實(shí)現(xiàn)線程有哪幾種方式晕翠?區(qū)別是什么喷舀?
三種方式:
1.通過(guò)繼承Thread類砍濒,重寫(xiě)該類的run()方法 2.實(shí)現(xiàn)runable接口 3.實(shí)現(xiàn)callable接口
通過(guò)實(shí)現(xiàn)runable和callable接口的方式來(lái)實(shí)現(xiàn)線程的話,可以同時(shí)繼承其他類硫麻,使得代碼更具有靈活性爸邢,同時(shí)在這種方式下,多個(gè)線程可以同時(shí)共享一個(gè)對(duì)象拿愧,非常適合多個(gè)相同的線程來(lái)處理同一份資源的情況杠河。訪問(wèn)當(dāng)前線程要使用Thread.currentThread()方法;通過(guò)繼承Thread類的方式來(lái)實(shí)現(xiàn)線程的話比較簡(jiǎn)單浇辜,可以直接使用this訪問(wèn)當(dāng)前的線程.券敌。
Thread類中的start和run方法的區(qū)別?(是否可以開(kāi)啟多線程)
通過(guò)start()方法來(lái)啟動(dòng)線程的時(shí)候柳洋,JVM處于一個(gè)就緒的狀態(tài)待诅,他會(huì)去調(diào)用run()方法來(lái)完成具體的業(yè)務(wù)邏輯,當(dāng)run()方法結(jié)束以后此線程就會(huì)終止熊镣,可以達(dá)到多線程的目的卑雁。如果我們直接使用run()方法,此時(shí)它只會(huì)被當(dāng)做一個(gè)普通方法來(lái)執(zhí)行绪囱,不能達(dá)到多線程的目的测蹲。
守護(hù)線程和非守護(hù)線程的區(qū)別?(垃圾回收線程例子)
java里線程分為用戶線程和守護(hù)線程鬼吵,用戶線程就是我們創(chuàng)建的普通線程弛房,守護(hù)線程就是為了服務(wù)用戶線程而存在的,比如我們的垃圾回收線程就是一個(gè)典型的守護(hù)線程而柑;當(dāng)我們的用戶線程都結(jié)束了,只剩下了守護(hù)線程的時(shí)候荷逞,它沒(méi)有了守護(hù)的對(duì)象媒咳,也就沒(méi)有了存在的必要,所以會(huì)殺死所有的守護(hù)線程种远,終止程序涩澡。
為什么wait, notify 和 notifyAll這些方法不在thread類里面?
因?yàn)閣ait notify notifyAll都是鎖級(jí)別的操作坠敷,而java提供的鎖是對(duì)象級(jí)別的不是線程級(jí)別的妙同,所以把他們定義在objiect類中。
Java中什么是競(jìng)態(tài)條件膝迎? 舉個(gè)例子說(shuō)明粥帚。
當(dāng)兩個(gè)線程去競(jìng)爭(zhēng)同一個(gè)資源的時(shí)候,如果對(duì)訪問(wèn)資源的順序敏感限次,那么就會(huì)出現(xiàn)競(jìng)態(tài)條件芒涡,產(chǎn)生競(jìng)態(tài)條件的區(qū)域的代碼稱為臨界區(qū)柴灯,我們可以在臨界區(qū)中使用適當(dāng)?shù)耐芥i就可以解決競(jìng)態(tài)條件。
Java中如何停止一個(gè)線程费尽?
在java中一般情況下我們是不需要去手動(dòng)停止一個(gè)線程的赠群,當(dāng)run()方法里面的業(yè)務(wù)執(zhí)行完成后它會(huì)自動(dòng)停止,如果我們需要手動(dòng)去停止一個(gè)線程有三種方法:
1.使用stop()方法旱幼,但是不推薦使用查描,因?yàn)檫@個(gè)是暴力停止線程,容易造成許多無(wú)法預(yù)料到的后果
2.使用flag標(biāo)志柏卤,并使用volatile關(guān)鍵字進(jìn)行修飾冬三。
3.使用interrupt()方法,這個(gè)方法本身是不能直接中斷線程的闷旧,我們需要去循環(huán)體里判斷isInterrupt()方法是否為true來(lái)確定線程是否被終止
參考鏈接:https://blog.csdn.net/u014270696/article/details/107596468
interrupted 和 isInterrupted 方法的區(qū)別长豁?
interrupt是用來(lái)中斷線程,標(biāo)記線程為中斷狀態(tài)
interrupted用來(lái)查詢線程的中斷狀態(tài)忙灼,并清除原狀態(tài)
isInterrupted也是用來(lái)查詢線程的中斷狀態(tài)匠襟,但是不會(huì)清除原狀態(tài)
sleep和wait的區(qū)別?
sleep和wait都是讓線程暫停執(zhí)行的方法。
sleep是Thread的方法疟游,可以放在任何位置亲雪,wait是object類中的方法,只能放在同步方法或者同步代碼塊里面啃勉。
sleep不會(huì)釋放 對(duì)象鎖,也就說(shuō)双妨,在同步方法或者同步代碼塊中使用的時(shí)候淮阐,一個(gè)線程訪問(wèn)時(shí),其他線程不能訪問(wèn)刁品。wait的話是會(huì)釋放 對(duì)象鎖的泣特。
在使用wait的時(shí)候,需要在另外一個(gè)線程中調(diào)用notify來(lái)進(jìn)行喚醒挑随,sleep不需要喚醒状您,他會(huì)等到休眠時(shí)間結(jié)束后自動(dòng)接著執(zhí)行。
如何在兩個(gè)線程間共享數(shù)據(jù)兜挨?(根據(jù)多個(gè)線程的代碼是否相同判斷是否使用同一個(gè)Runnable對(duì)象)
如果每個(gè)線程的代碼一樣膏孟,可以使用同一個(gè)runnable對(duì)象,比如說(shuō)我們的賣(mài)票系統(tǒng)
如果每個(gè)線程的代碼不一樣拌汇,可以使用不同的runnable對(duì)象柒桑,比如說(shuō)我們的銀行存取款
java的內(nèi)存模型? (待解決~)
首先說(shuō)出和內(nèi)存結(jié)構(gòu)的區(qū)別噪舀、然后是為什么需要內(nèi)存模型(從計(jì)算機(jī)發(fā)展的角度來(lái)看逐步過(guò)渡到原子性幕垦、可見(jiàn)性丢氢、有序性),最后就是java內(nèi)存模型如何解決上面三個(gè)問(wèn)題先改;
有三個(gè)線程T1疚察,T2,T3仇奶,怎么確保它們按順序執(zhí)行貌嫡?
(多個(gè)方法,常見(jiàn)的join極其機(jī)制)
第一種方法:先執(zhí)行最后一個(gè)線程T3,然后T3調(diào)用T2,T2調(diào)用T1
第二種方法:使用join()方法 join方法的主要作用就是同步该溯, 可以是線程由并行變換為串行岛抄,相當(dāng)于我在線程A中調(diào)用了B的join()方法,那么A線程會(huì)等待B線程執(zhí)行完后才會(huì)執(zhí)行狈茉;
參考:https://www.cnblogs.com/lcplcpjava/p/6896904.html
Thread類中的yield方法有什么作用夫椭?
作用是暫停當(dāng)前正在執(zhí)行的線程對(duì)象,讓其它有相同優(yōu)先級(jí)的線程執(zhí)行氯庆,靜態(tài)方法蹭秋,只是可能性,不能保證確定性
線程的生命周期包括哪幾個(gè)階段堤撵?
線程的生命周期包含5個(gè)階段仁讨,包括:新建、就緒实昨、運(yùn)行洞豁、阻塞、銷毀荒给。
新建:就是剛new出來(lái)的時(shí)候
就緒:剛執(zhí)行start()方法后丈挟,線程處于等待被cpu分配資源的階段
運(yùn)行:線程獲得CPU資源進(jìn)入運(yùn)行階段
阻塞:當(dāng)線程在執(zhí)行的時(shí)候,因?yàn)橐恍┰蜃兂闪俗枞麪顟B(tài)志电,比如使用sleep()或者wait()方法后曙咽。
銷毀:當(dāng)線程執(zhí)行完任務(wù),或者由于異常導(dǎo)致結(jié)束溪北,或者我們強(qiáng)行終止任務(wù)的時(shí)候,線程需要被銷毀夺脾。
二之拨、線程池
為什么要使用線程池?
技巧:什么是線程池咧叭,為什么要用蚀乔?
線程池是一種線程的使用模式,一個(gè)線程池中可以有多個(gè)線程菲茬,線程池就是創(chuàng)建若干個(gè)可執(zhí)行的線程放在一個(gè)池里面吉挣,當(dāng)我們有任務(wù)需要處理的時(shí)候派撕,就會(huì)把任務(wù)提交到線程池中的任務(wù)隊(duì)列里面,交給他進(jìn)行處理睬魂,處理完以后線程不會(huì)被銷毀终吼,而是繼續(xù)會(huì)等待下一次被調(diào)用。(舉例:公交車(chē)?yán)樱?br>
線程池好處:假如說(shuō)我們有50000個(gè)請(qǐng)求需要處理氯哮,并且每一個(gè)請(qǐng)求都需要單獨(dú)為它創(chuàng)建一個(gè)線程际跪,那么我們需要?jiǎng)?chuàng)建50000個(gè)線程來(lái)處理這些請(qǐng)求,一個(gè)線程的話的創(chuàng)建 執(zhí)行 銷毀都需要時(shí)間喉钢,那么如果我們使用線程池的話姆打,那么可以大幅度減少線程的創(chuàng)建和銷毀的時(shí)間,同時(shí)也可以對(duì)這些線程進(jìn)行管理肠虽,提高工作的效率幔戏。
使用過(guò)哪些線程池?有什么使用場(chǎng)景税课?
newSingleThreadExcutor 它的特點(diǎn)是線程池中只有一個(gè)線程闲延,每次執(zhí)行一個(gè)任務(wù)
newFixedThreadPool它的特定是在線程中有固定線程數(shù)量,空閑線程會(huì)一直保留
newCachedThreadPool它的特點(diǎn)就是在有任務(wù)時(shí)才會(huì)創(chuàng)建線程伯复,空閑線程保留60秒
newScheduledThreadPool它的特點(diǎn)是創(chuàng)建一個(gè)大小無(wú)限的線程池慨代,線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。
線程池的七個(gè)參數(shù)的作用
線程池中有幾個(gè)重要的參數(shù)
threadFactory :線程工廠啸如,用來(lái)創(chuàng)建線程
keepAliveTime :線程沒(méi)有任務(wù)時(shí)最多保持多久時(shí)間終止
unit :keepAliveTime的時(shí)間單位
corePoolSize :核心線程數(shù)量
maximumPoolSize :線程最大線程數(shù)
workQueue :阻塞隊(duì)列侍匙,存儲(chǔ)等待執(zhí)行的任務(wù)
rejectHandler :當(dāng)拒絕處理任務(wù)時(shí)的策略
線程池的工作隊(duì)列(workQueue )有哪些?
有一個(gè)基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列
有一個(gè)基于鏈表結(jié)構(gòu)的阻塞隊(duì)列
有一個(gè)不儲(chǔ)存元素的阻塞隊(duì)列
有一個(gè)具有優(yōu)先級(jí)的無(wú)限阻塞隊(duì)列
線程池的拒絕策略?
線程池通常會(huì)有四種拒絕策略:第一種是丟棄任務(wù)并拋出拒絕執(zhí)行異常叮雳;第二種是丟棄任務(wù)想暗,但是不拋出異常;第三種是丟棄隊(duì)列最前面的任務(wù)帘不,然后重新提交被拒絕的任務(wù) 说莫;第四種是由提交任務(wù)的線程處理當(dāng)前這個(gè)任務(wù)。默認(rèn)的話是使用的第一種丟棄任務(wù)并拋出拒絕執(zhí)行異常的策略寞焙。
線程池的執(zhí)行流程储狭?
1.當(dāng)有任務(wù)進(jìn)來(lái)時(shí),首先判斷核心線程池里面是否有線程可以執(zhí)行捣郊,有空閑線程的話辽狈,會(huì)創(chuàng)建線程執(zhí)行任務(wù)
2.如果核心線程池沒(méi)有線程可以執(zhí)行任務(wù)了,會(huì)把任務(wù)丟到任務(wù)隊(duì)列中
3.如果任務(wù)隊(duì)列也已經(jīng)滿了呛牲,但運(yùn)行線程小于最大的線程數(shù)量刮萌,那么會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù),如果運(yùn)行線程已經(jīng)達(dá)到最大的線程數(shù)量的時(shí)候娘扩,那么此時(shí)就無(wú)法創(chuàng)建更多的線程去執(zhí)行任務(wù)了着茸,執(zhí)行拒絕策略壮锻。
execute和submit的區(qū)別?
他們都是屬于線程池的方法
executee只能提交Runnable類型的任務(wù)涮阔,會(huì)直接拋出任務(wù)執(zhí)行時(shí)的異常猜绣,適用于不需要關(guān)注返回值的場(chǎng)景;
submit可以提交Runnable和Callable類型任務(wù)澎语, 并且會(huì)吃掉異常途事,所以適用于只需要關(guān)注返回值的場(chǎng)景
三、鎖系列
你能說(shuō)簡(jiǎn)單說(shuō)一下synchronize嗎擅羞?
synchronize是java中的關(guān)鍵字尸变,可以用來(lái)修飾局部變量、方法减俏、類召烂、代碼塊等;主要有三種作用:可以確保原子性娃承、可見(jiàn)性奏夫、有序性,原子性就是能夠保證同一時(shí)刻有且只有一個(gè)線程在操作共享數(shù)據(jù)历筝,其他線程必須等該線程處理完數(shù)據(jù)后才能進(jìn)行酗昼;可見(jiàn)性就是當(dāng)一個(gè)線程在修改共享數(shù)據(jù)時(shí),其他線程能夠看到梳猪,保證可見(jiàn)性麻削,volatile關(guān)鍵字也有這個(gè)功能;有序性就是春弥,被synchronize鎖住后的線程相當(dāng)于單線程呛哟,在單線程環(huán)境jvm的重排序是不會(huì)改變程序運(yùn)行結(jié)果的,可以防止重排序?qū)Χ嗑€程的影響匿沛∩ㄔ穑‘
延伸一:java內(nèi)存模型的三大特性,或者是說(shuō)一下java內(nèi)存模型逃呼,或者是synchronize跟java內(nèi)存模型有什么關(guān)系嗎鳖孤?
1、什么是java內(nèi)存模型:java虛擬機(jī)規(guī)范中定義了java內(nèi)存模型是用來(lái)屏蔽各種硬件和操作系統(tǒng)間內(nèi)存的差異抡笼,來(lái)實(shí)現(xiàn)java程序在各平臺(tái)下并發(fā)一致性苏揣,再就是,java內(nèi)存模型并不是真實(shí)存在的蔫缸,他只是一種抽象概念腿准,定義了線程和主內(nèi)存之間的抽象關(guān)系际起,也就是線程之間的共享變量存儲(chǔ)在主內(nèi)存中拾碌,每個(gè)線程都有一個(gè)私有的本地內(nèi)存吐葱,本地內(nèi)存存儲(chǔ)了該線程共享變量的副本。
2校翔、java內(nèi)存模型的三大特性:java內(nèi)存模型有三大特性弟跑,原子性、可見(jiàn)性防症、有序性孟辑。
原子性:要么執(zhí)行,要么不執(zhí)行蔫敲,主要使用互斥鎖Synchronize或者lock來(lái)保證操作的原子性饲嗽;
可見(jiàn)性:在變量修改后將新值同步回主內(nèi)存,主要有兩種實(shí)現(xiàn)方式奈嘿,一是volatile貌虾,被volatile修飾的變量發(fā)生修改后會(huì)立即刷新到主內(nèi)存;二是使用Synchronize或者lock裙犹,當(dāng)一個(gè)變量unlock之前會(huì)將變量的修改刷新到主內(nèi)存中尽狠;
有序性:在Java內(nèi)存模型中,允許編譯器和處理器對(duì)指令進(jìn)行重排序叶圃,但是重排序不會(huì)影響單線程的執(zhí)行結(jié)果袄膏,卻會(huì)影響多線程并發(fā)執(zhí)行的正確性。主要有兩種方式確保有序性:volatile 和 Synchronize 關(guān)鍵字掺冠,volatile是通過(guò)添加內(nèi)存屏障的方式來(lái)禁止指令重排序沉馆,也就是重排序是不能把后面的指令放到內(nèi)存屏障之前執(zhí)行;Synchronize是保證同一時(shí)刻有且只有一個(gè)線程執(zhí)行同步代碼赫舒,類似于串聯(lián)順序執(zhí)行代碼悍及。
延伸二:你了解先行發(fā)生原則(happens-before)嗎?
為什么會(huì)出現(xiàn)先行發(fā)生原則:從上邊我們也能看到接癌,如果java內(nèi)存模型中所有的有序性都要靠volatile和Synchronize來(lái)實(shí)現(xiàn)的話心赶,那么是非常繁瑣的,所以j就出現(xiàn)這么一個(gè)《先行發(fā)生原則》缺猛,用來(lái)判斷數(shù)據(jù)是否存在競(jìng)爭(zhēng)缨叫、線程是否安全的重要依據(jù)。
先行發(fā)生原則是java內(nèi)存模型用來(lái)定義兩個(gè)操作之間的偏序關(guān)系荔燎。比如說(shuō)A操作先發(fā)生于B操作耻姥,那么在B操作發(fā)生之前,A操作修改了內(nèi)存中的共享變量有咨,那么就會(huì)被B操作察覺(jué)到琐簇。
延伸三:volatile的作用,volatile跟Synchronize的區(qū)別
volatile的作用:volatile關(guān)鍵字主要作用是確保可見(jiàn)性跟有序性婉商,當(dāng)一個(gè)共享變量被volatile修飾似忧,如果一個(gè)線程修改了這個(gè)共享變量,那么其他線程就會(huì)立馬可知丈秩,強(qiáng)制刷新到主內(nèi)存盯捌。
volatile跟Synchronize的區(qū)別:
volatile只能作用局部變量,Synchronize可作用局部變量蘑秽、方法饺著、類、同步代碼塊等肠牲;
volatile只能保證可見(jiàn)性和有序性幼衰,不能保證原子性,Synchronize三者都可以保證缀雳。
volatile不會(huì)造成線程阻塞塑顺,Synchronize可能會(huì)造成線程阻塞。
在性能方面synchronized關(guān)鍵字是防止多個(gè)線程同時(shí)執(zhí)行一段代碼俏险,會(huì)影響程序執(zhí)行效率严拒,而volatile關(guān)鍵字在某些情況下性能要優(yōu)于synchronized。
延伸四:你能說(shuō)說(shuō)你剛剛提到的重排序嗎竖独?
重排序是編譯器和處理器為了優(yōu)化程序性能而對(duì)指令進(jìn)行重新排序的一種手段裤唠。重排序可以保證最終執(zhí)行的結(jié)果是與程序順序執(zhí)行的結(jié)果一致,并且只會(huì)對(duì)不存在數(shù)據(jù)依賴性的指令進(jìn)行重排序莹痢,重排序在單線程下對(duì)最終執(zhí)行結(jié)果是沒(méi)有影響的种蘸,但是在多線程下就會(huì)存在問(wèn)題。
舉個(gè)例子:https://www.cnblogs.com/niceyoo/p/12549327.html
你能說(shuō)一下Synchronize底層原理嗎竞膳?
synchronized的底層原理是跟monitor有關(guān)航瞭,也就是視圖器鎖,每個(gè)對(duì)象都有一個(gè)關(guān)聯(lián)的monitor坦辟,當(dāng)Synchronize獲得monitor對(duì)象的所有權(quán)后會(huì)進(jìn)行兩個(gè)指令:加鎖指令monitorenter跟減鎖指令monitorexit刊侯。
monitor里面有個(gè)計(jì)數(shù)器,初始值是從0開(kāi)始的锉走。如果一個(gè)線程想要獲取monitor的所有權(quán)滨彻,就看看它的計(jì)數(shù)器是不是0,如果是0的話挪蹭,那么就說(shuō)明沒(méi)人獲取鎖亭饵,那么它就可以獲取鎖了,然后將計(jì)數(shù)器+1梁厉,也就是執(zhí)行monitorenter加鎖指令辜羊;monitorexit減鎖指令是跟在程序執(zhí)行結(jié)束和異常里的,如果不是0的話,就會(huì)陷入一個(gè)堵塞等待的過(guò)程八秃,直到為0等待結(jié)束庇麦。
Synchronize在JDK1.6之后做了什么樣的優(yōu)化?
自旋鎖 鎖消除 鎖粗化 輕量級(jí)鎖 偏向鎖
參考資料:https://www.cnblogs.com/jiangds/p/6476293.html
.Synchronized 加在普通方法上鎖的對(duì)象是什么,加在靜態(tài)方法上鎖住的對(duì)象是什么?
Synchronized修飾非靜態(tài)方法喜德,實(shí)際上是對(duì)調(diào)用該方法的對(duì)象加鎖,俗稱“對(duì)象鎖”垮媒。
Synchronized修飾靜態(tài)方法舍悯,實(shí)際上是對(duì)該類對(duì)象加鎖,俗稱“類鎖”睡雇。
Synchronized(this) 和 Synchronized (User.class) 的區(qū)別 :
1.對(duì)于靜態(tài)方法的萌衬,由于jvm加載的時(shí)候還沒(méi)有對(duì)象產(chǎn)生,所以只能使用類鎖它抱,就是類名.class 秕豫,只要使用類鎖就會(huì)攔截所有線程,只讓一個(gè)線程可以訪問(wèn)
2.對(duì)于普通方法观蓄,默認(rèn)的使用對(duì)象鎖混移,可以直接使用this來(lái)表示。對(duì)于同一個(gè)對(duì)象的話侮穿,是按照順序進(jìn)行訪問(wèn)歌径,對(duì)于不同對(duì)象可以同時(shí)訪問(wèn)。
參考:https://blog.csdn.net/qq_21479345/article/details/100574968
Synchronized和Lock的區(qū)別
從存在層次 鎖的獲取 鎖的類型 鎖的狀態(tài) 鎖的釋放 性能方面來(lái)說(shuō)
他們都是可重入鎖
存在層次:Synchronizeds是java的關(guān)鍵字亲茅,lock是一個(gè)接口
獲取鎖:Synchronizeds獲取鎖的話是假設(shè)A獲取了鎖回铛,那么B會(huì)等待,假如A阻塞了克锣,那么B會(huì)一直等待茵肃;Lock獲取鎖的方法比較多,常見(jiàn)的是lock()方法和trylock()方法
鎖的狀態(tài):Synchronizeds無(wú)法判斷鎖的狀態(tài)袭祟,Lock可以判斷鎖的狀態(tài)
鎖的類型:Synchronizeds可重入验残,不可中斷,非公平巾乳; Lock的話可重入可判斷可公平
鎖的釋放:Synchronizeds可以自動(dòng)釋放鎖胚膊;Lock必須在finally中釋放鎖,不然容易造成死鎖
適用性:Synchronizeds適合于少量同步代碼的想鹰,Lock適合大量同步代碼的
圖片不清晰:https://blog.csdn.net/u012403290/article/details/64910926
何謂悲觀鎖與樂(lè)觀鎖紊婉?樂(lè)觀鎖和悲觀鎖的使用場(chǎng)景
悲觀鎖:就是把事情往最壞的方向去考慮,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為會(huì)對(duì)數(shù)據(jù)進(jìn)行更改辑舷,所以只要有人拿數(shù)據(jù)就會(huì)上鎖喻犁,其他人只能等待直到他拿完了才能去拿。我們比較常見(jiàn)的悲觀鎖有Synchronized,ReentrantLock
樂(lè)觀鎖:把事情都往好的方向去考慮,每次去拿數(shù)據(jù)的時(shí)候都會(huì)認(rèn)為不會(huì)對(duì)數(shù)據(jù)進(jìn)行更改肢础,但是他會(huì)在更新的時(shí)候去判斷一下數(shù)據(jù)有沒(méi)有被更改还栓。樂(lè)觀鎖適用于讀數(shù)據(jù)比較多的情況,可以提高吞吐量传轰。悲觀鎖的話更適合于寫(xiě)比較多的情況剩盒。
參考資料:https://blog.csdn.net/qq_34337272/article/details/81072874
四、線程工具類
ThreadLocal的作用和原理慨蛙?
ThreadLocal是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類辽聊,通過(guò)它可以在指定的線程中存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)以后期贫,只有在指定的線程中可以獲取到存儲(chǔ)的數(shù)據(jù)跟匆,對(duì)于其他線程來(lái)說(shuō)則無(wú)法取到數(shù)據(jù)。
ThreadLocal的實(shí)現(xiàn)原理:
ThreadLocal的實(shí)現(xiàn)原理主要是依據(jù)它的get和set方法通砍,從set()方法的源碼中我們可以了解到他是先調(diào)用getmap()方法獲取當(dāng)前線程的ThreadLocalMap對(duì)象玛臂,類似于我們的hashmap 是以鍵值對(duì)的方式來(lái)保存數(shù)據(jù)的,key是TheadLocal封孙,當(dāng)前的線程迹冤,value是保存的值;從get()方法的源碼我們同樣也可以發(fā)現(xiàn)虎忌,他是先調(diào)用getmap()方法獲取當(dāng)前線程的ThreadLocalMap對(duì)象叁巨,然后根據(jù)key的值來(lái)獲取對(duì)應(yīng)的value,由于所有操作都是基于同一個(gè)ThreadLocalMap對(duì)象,所以在多線程中可以互不干擾的存儲(chǔ)和修改數(shù)據(jù)呐籽。