Num1:同步訪問共享的可變資料
關鍵字Synchronized
可以保證在同一時刻,只有一個執行緒可以執行某一個方法,或者某一個程式碼塊。、
同步不僅僅理解為互斥的方式,如果沒有同步,一個執行緒的變化就不能被其他執行緒看到。同步不僅可以阻止一個執行緒看到物件處於不一致的狀態中,它還可以保證進入同步方法或者同步程式碼塊的每個執行緒,都看到由同一個鎖保護之前的所有修改效果。
基本版本:
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
改善版本:
public class StopThread {
private static volatile boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
簡而言之,當多個執行緒共享可變資料的時候,每個讀或者寫資料的執行緒都必須執行同步。如果沒有同步,就無法保證一個執行緒所做的修改可以被另一個執行緒獲知,未能同步共享可變的資料或造成程式的活性失敗和安全性失敗。
Num2:executor和task優先於執行緒
如何建立一個工作佇列呢,一行程式碼。
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(runnable);
executor.shutdown();
如果想讓不止一個執行緒來處理來自這個佇列的請求,只要呼叫一個不同的靜態工廠,這個工廠建立了一種不同的executor service,稱作執行緒池(thread pool)
。
Num3:慎用延遲初始化
延遲初始化是延遲到需要域的是值時才將它初始化的這種行為。如果永遠不需要這個值,這個域就永遠不會被初始化。這種方法既適用於靜態域,也適用於例項域。雖然延遲初始化主要是一種優化,但它也可以用來打破類和例項初始化的有害迴圈。
在大多數情況下,正常的初始化要優先於延遲初始化。
- 如果利用延遲優化來破壞初始化的迴圈,就要使用同步的訪問方法。
- 如果出於效能的考慮而需要對靜態域使用延遲初始化,就用
lazy initialization holder class
模式。 - 如果出於效能的考慮而需要對例項域使用延遲初始化,就用雙重檢查模式
double-check idiom
。 單重檢查模式
single-check idiom
。
示例程式碼:
public class Initialization {
// Normal initialization of an instance field - Page 282
private final FieldType field1 = computeFieldValue();
// Lazy initialization of instance field - synchronized accessor - Page 282
private FieldType field2;
synchronized FieldType getField2() {
if (field2 == null)
field2 = computeFieldValue();
return field2;
}
// Lazy initialization holder class idiom for static fields - Page 283
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
static FieldType getField3() {
return FieldHolder.field;
}
// Double-check idiom for lazy initialization of instance fields - Page 283
private volatile FieldType field4;
FieldType getField4() {
FieldType result = field4;
if (result == null) { // First check (no locking)
synchronized (this) {
result = field4;
if (result == null) // Second check (with locking)
field4 = result = computeFieldValue();
}
}
return result;
}
// Single-check idiom - can cause repeated initialization! - Page 284
private volatile FieldType field5;
private FieldType getField5() {
FieldType result = field5;
if (result == null)
field5 = result = computeFieldValue();
return result;
}
private static FieldType computeFieldValue() {
return new FieldType();
}
}
class FieldType {
}