第5章 定時器Timer
- 創(chuàng)建一個Timer就是啟動一個新的線程。
第6章 章例模式與多線程
如何使單例模式遇到多線程是安全的、正確的。
1.立即加載/“餓漢模式”
//在類初始化時就創(chuàng)建了靜態(tài)對象,不管以后使不使用都會占據(jù)一定內(nèi)存
public class Singleton {
private Singleton(){}
private static final Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
2.延遲加載/"懶漢模式"
//在第一次使用時實(shí)例化對象 Double-Check-Lock
//相傳在JDK1.5之前這個雙重檢查也是有問題的但之后修復(fù)了
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null)//避免加大塊鎖效率低
synchronized (Singleton.class) {
if (instance == null)//避免并發(fā)時的錯誤
instance = new Singleton();
}
return instance;
}
}
3.靜態(tài)內(nèi)部類實(shí)現(xiàn)單例
public class Singleton {
private Singleton(){}
/*
*1.此處要用到類中靜態(tài)屬性變量的特性:
* 靜態(tài)變量屬于類并非對象,在類加載時就初始化完畢且就一次
*2.因內(nèi)部內(nèi)類中的靜態(tài)的屬性,所以此內(nèi)部類需聲明成靜態(tài)內(nèi)部類(說明見下)
*3.靜態(tài)內(nèi)部類在第一次使用時完成加載(說明見下)
*/
private static class InnerSingleton {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InnerSingleton.instance;
}
}
對上述第二條的解釋(來自互聯(lián)網(wǎng)):java類加載順序,首先加載類,執(zhí)行static變量初始化,接下來執(zhí)行對象的創(chuàng)建,如果我們要執(zhí)行代碼中的內(nèi)部類靜態(tài)變量的初始化,那么必須先執(zhí)行加載外部類,再加載內(nèi)部類,最后初始化內(nèi)部類中的靜態(tài)變量,問題就出在加載內(nèi)部類上面,我們可以把內(nèi)部類看成外部類的非靜態(tài)成員,它的初始化必須在外部類對象創(chuàng)建以后進(jìn)行,要加載內(nèi)部類必須在實(shí)例化外部類之后完成,java虛擬機(jī)要求所有的靜態(tài)變量必須在對象創(chuàng)建之前完成,這樣便產(chǎn)生了矛盾。
對上述第三條的解釋(來自互聯(lián)網(wǎng)):靜態(tài)內(nèi)部類的加載不需要依附外部類,在使用時才加載。不過在加載靜態(tài)內(nèi)部類的過程中也會加載外部類。靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類一樣,都是在被調(diào)用時才會被加載。
4.靜態(tài)代碼塊實(shí)現(xiàn)單例
//靜態(tài)代碼塊中的代碼在使用類的時候就已經(jīng)執(zhí)行了,所以可以應(yīng)用這個特性來實(shí)現(xiàn)單例
public class Singleton {
private Singleton(){}
private static Singleton instance = null;
static {
instance = new Singleton();
}
public static Singleton getInstance() {
return instance;
}
}
5.枚舉實(shí)現(xiàn)單例
//enum類型的值實(shí)際上是通過在運(yùn)行期構(gòu)造出對象來表示的
//可以說使用的時候其實(shí)就是個已經(jīng)初始化好了的對象
public enum Singleton {
INSTANCE
}
上述前四種在序列化對象再通過反序列化得到對象時得到的結(jié)果還是多例的,解決辦法如下:
//這就麻煩了,因?yàn)槿绻藛沃腥绻衅渌鼘ο蟮脑掃€得弄成transient的 protected Object readResolve() throws ObjectStreamException { return someInstance;//單例對象 }但枚舉類型單例不存在序列化這個問題
第7章 拾遺增補(bǔ)
- 線程狀態(tài):NEW,RUNNABLE,TERMINATED,TIMED_WAITING,BLOCKED,WAITING
myThread.getState();
- 線程組:可以指的管理線程或線程組對象,有效地對線程或線程組對象進(jìn)行組織。
ThreadGroup group = new ThreadGroup("Group_Name");//線程組
Thread t1 = new Thread(group, new Thread(...));//管理線程
- 線程中出現(xiàn)異常的處理
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
publi void uncaughtException(Thread t, Throwable e) {
//some logic
e.printStackTrace();
}
}
t1.start();
}
- 方法
setUncaughtExceptionHandler()是給指定線程對象設(shè)置的anip處理器。在Thread類中還可以使用setDefaultUncaughtExceptionHandler()方法對所有線程對象設(shè)置異常處理器。
public static void main(String[] args) {
MyThread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlert() {
@Override
public void uncaughtException(Thread t, Throwable e) {
//some logic
e.printStrackTrace();
}
}
MyThread t1 = new MyThread();
t1.start();
}