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 {
}