Item 66. Synchronize access to shared mutable data
(1) 用 synchronized 关键字可以保证
1.1 其他的thread不会看到inconsistent 状态的变量, 即mutual exclusion
1.2 每个thread都会看到变量的最新状态,这一点非常重要,即communication purpose
(2) Java中,除了long和double意外的变量进行读写操作都是atomic的。
但是,atomic并不能保证 a value written by one thread will be visible to another,因此对于atomic的操作有时也是需要synchronized。例如一下例子中虽然主线程会将stopRequested设为true,但是并没有保证新线程什么时候会看到这个变化,再加上虚拟机的代码优化可能导致死循环。
// Broken! - How long would you expect this program to run?
public class StopThread {
private static 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;
}
}
应该加上synchronized关键字:
// Properly synchronized cooperative thread termination
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();
}
}
(3) “synchronization has no effect unless both read and write operations are synchronised.”
(4) volatile关键字不能起到mutual exclusive作用,但是在上例中可以起到communication作用,即让每个thread看到这个变量的最新状态。
private static volatile boolean stopRequested;
由于volative不能起到mutual exclusive作用,一下代码会出错,解决办法是用synchronized代替volatile
// Broken - requires synchronization!
private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
return nextSerialNumber++;
}
Item 67. Avoid excessive synchronization
(1) Inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object.否则有可能导致死锁等问题。
(2) As a rule, you should do as little work as possible inside synchronized regions.
(3) 过度使用synchronization会导致performance下降。在现代计算机中,性能下降主要并不是体现在等待锁上,而是失去了很多parallelism和代码优化机会。
Item 68. Prefer executors and tasks to threads
Executors.newCachedThreadPool,新提交的task不会被queue,而是新建一个thread来执行,如果server load已经很重会make things worse。但是优点是不用复杂的configuration。
Executors.newFixedThreadPool,只新建特定数量的thread来处理queue中的tasks。
Item 69. Prefer concurrency utilities to wait and notify
(1)尽量使用JAVA中concurrency下的库,例如ConcurrentHashMap,而不是用Collections.synchronizedMap 或者 Hashtable。
最常用的synchronizers包括CountDownLatch和Semaphore。
(2)如果要用wait,一定要套用以下代码:Always use the wait loop idiom to invoke the wait method; never invoke it outside of a loop。
synchronized (obj) {
while (<condition does not hold>)
obj.wait(); // (Releases lock, and reacquires on wakeup)
... // Perform action appropriate to condition
}
(3)尽量使用notifyAll来代替notify,因为notifyAll并不会导致程序运行错误(等待的线程即使被notify也会再次检查condition)
Item 70. Document thread safety
Item 71. Use lazy initialization judiciously
如果能够不用lazy initialisation就尽量不用
Item 72. Don’t depend on the thread scheduler
Item 73. Avoid thread groups