字符串
- java字符串使用+進(jìn)行拼接時(shí)钟沛,編譯器會(huì)通過(guò)StringBuilder進(jìn)行優(yōu)化悠咱。但是在循環(huán)體中使用+=的時(shí)候會(huì)創(chuàng)建多個(gè)StringBuilder迎卤,可以在循環(huán)體外顯式使用StringBuilder蔗草,可以使得程序效率更高
- Buffer是線程安全的零远,所以在單線程的情況先執(zhí)行效率低于Builder
單例的寫法
單例一般有兩種寫法,也將其稱為惡漢式和懶漢式正驻,我這里說(shuō)的是在沒(méi)有 lazy load 等考慮的情況下
沒(méi)有帶參數(shù)的寫法:
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return INSTANCE;
}
}
帶參數(shù)的寫法:
public class Singleton {
private volatile static Singleton sInstance;
private static final Object LOCK = new Object();
private Singleton(Param param){
// do some init
}
public static Singleton getInstance(Param param) {
if (sInstance == null) {
synchronized (LOCK) {
if (sInstance == null) {
sInstance = new Singleton(param);
}
}
}
return sInstance;
}
}
關(guān)于為何需要雙重判空網(wǎng)上有很多介紹的文章弊攘,這里不再多說(shuō),需要注意的是需要使用volatile防止重排序問(wèn)題
this逃逸
this逃逸主要指在構(gòu)造方法沒(méi)有執(zhí)行完畢的情況下姑曙,其他線程獲取到了這個(gè)對(duì)象的引用襟交。需要小心在構(gòu)造方法中不要使用一些異步手段將this對(duì)象發(fā)布出去。
并發(fā) 多線程相關(guān)
- 使用 synchronized 關(guān)鍵字同步對(duì)象的時(shí)候應(yīng)該在使用對(duì)象的地方都使用 synchronized來(lái)包裹伤靠,否則沒(méi)有同步效果
- 將不可變的對(duì)象用 final 來(lái)修飾可以減少很多同步的問(wèn)題捣域。final并不表示對(duì)象的內(nèi)容不會(huì)變化,只是說(shuō)不能再賦值。相當(dāng)于一個(gè)指針指向的地址確定了竟宋,但是內(nèi)容沒(méi)有限制
- 正確的中斷線程:
class MyThread extends Thread {
public void run() {
try {
doSomeThing();
} catch (InterruptedException e) {
doCancel();
}
}
public void cancel() {
interrupt();
}
}
還有一種方法是通過(guò)在 cancel
方法中設(shè)置標(biāo)志位來(lái)取消線程也是可以的零聚,注意將標(biāo)志位設(shè)置為 volatile
并且正確的處理中斷
- 線程池的設(shè)置:線程池有三種系奉,計(jì)算密集線程池瞬矩、IO線程池攒磨,newThread(考慮到有可能希望某個(gè)任務(wù)及早執(zhí)行而不是在線程池中排隊(duì))。其中計(jì)算密集型線程池的大小建議為$N(cpu核數(shù))+1$蜗字,具體參見(jiàn) 《Java并發(fā)編程實(shí)戰(zhàn)》 8.2 設(shè)置線程池大小
- 線程如果在處理不可打斷的任務(wù)打肝,應(yīng)該在出現(xiàn)中斷的時(shí)候?qū)⒅袛酄顟B(tài)保存起來(lái),然后在任務(wù)執(zhí)行完了之后挪捕,再響應(yīng)中斷
class MyThread extends Thread {
private volatile boolean interrupted = false;
public void run() {
try {
while (true) {
try {
doSomeThing();
} catch (InterruptedException e) {
interrupted = true;
}
}
} finally {
if (interrupted)
Thread.currentThread().interrupted();
}
}
public void cancel() {
interrupted = true;
}
}
- Thread#join() 方法可以讓當(dāng)前線程等待目標(biāo)線程執(zhí)行結(jié)束粗梭,如果目標(biāo)線程已經(jīng)結(jié)束,則執(zhí)行當(dāng)前線程后面的代碼级零,否則必須等待目標(biāo)線程結(jié)束之后(如果設(shè)置了超時(shí)時(shí)間断医,超時(shí)和目標(biāo)線程結(jié)束兩個(gè)條件滿足一個(gè)即可)能執(zhí)行后面的代碼。使用join()方法解決定時(shí)任務(wù)提前結(jié)束引起的一些問(wèn)題奏纪,具體參見(jiàn) 《Java并發(fā)編程實(shí)戰(zhàn)》 7.1.4 示例:計(jì)時(shí)運(yùn)行
static
- 使用private static編譯器會(huì)優(yōu)先考慮將方法內(nèi)聯(lián)
- 無(wú)論實(shí)例化幾次或者調(diào)用幾次方法,static代碼段都執(zhí)行一次...比如,你創(chuàng)建了類的兩個(gè)實(shí)例,但是只有創(chuàng)建第一個(gè)實(shí)例的時(shí)候static代碼段才被執(zhí)行.創(chuàng)建第二個(gè)的時(shí)候?qū)⒉粓?zhí)行...使用類名調(diào)用靜態(tài)方法也同理
- 在實(shí)例化一個(gè)對(duì)象的時(shí)候也被調(diào)用.而且先于構(gòu)造函數(shù)被調(diào)用.也就是說(shuō),我們創(chuàng)建一個(gè)對(duì)象,那么首先先調(diào)用static代碼段,然后再調(diào)用構(gòu)造函數(shù)
強(qiáng)引用鉴嗤、弱引用、軟引用序调、虛引用
強(qiáng)引用
強(qiáng)引用是使用最普遍的引用醉锅。當(dāng)內(nèi)存空間不足,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯(cuò)誤发绢,使程序異常終止硬耍,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題
Object o=new Object(); // 強(qiáng)引用
軟引用
如果一個(gè)對(duì)象只具有軟引用,則內(nèi)存空間足夠边酒,垃圾回收器就不會(huì)回收它经柴;如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存甚纲。只要垃圾回收器沒(méi)有回收它口锭,該對(duì)象就可以被程序使用朦前。軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存介杆。
String str=new String("abc"); // 強(qiáng)引用
SoftReference<String> softRef=new SoftReference<String>(str); // 軟引用
弱引用
弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中韭寸,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象春哨,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存恩伺。不過(guò)赴背,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。
String str=new String("abc");
WeakReference<String> abcWeakRef = new WeakReference<String>(str);
str=null;
虛引用
虛引用顧名思義凰荚,就是形同虛設(shè)燃观,與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期便瑟。如果一個(gè)對(duì)象僅持有虛引用缆毁,那么它就和沒(méi)有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收到涂。
幾種引用方式在垃圾回收時(shí)候的區(qū)別
Java中父類與子類中靜態(tài)代碼段脊框、非靜態(tài)代碼段和構(gòu)造方法的執(zhí)行過(guò)程
執(zhí)行流程為:
父類靜態(tài)代碼段->子類靜態(tài)代碼段->父類非靜態(tài)代碼段->父類構(gòu)造方法->子類非靜態(tài)代碼段->父類構(gòu)造方法
在子類的構(gòu)造方法執(zhí)行前必然會(huì)執(zhí)行父類的構(gòu)造方法,如果指明了super(params)
践啄,則執(zhí)行父類中對(duì)應(yīng)的構(gòu)造方法浇雹,否則執(zhí)行默認(rèn)沒(méi)有參數(shù)的構(gòu)造方法
參考: