|Practical Java| Chapter 5 Multithreading
for ease and speed in doing a thing do not give the work lasting solidity or
exactress of beauty!. ----Plutarch, life of Pericles
要进行多线程编程, 首先该好好理解并发编程原理(concurrent programming).
("Instance 函数或者变量 " --- 指的是类的成员)
46> 面对 Instance 函数, synchronized锁定的是对象而非函数或代码.
关键字 synchronized 可用作函数的修饰符(Modifier), 亦可以用作函数的
语句. 应该注意到这里的xynchronized 并不是平常认为的互拆器(mutex)
或者关键区 (critical section).
对于 Instance 方法, 关键词 synchronized 其实并不锁定函数或代码, 她锁
定的是对象, Remember: 每个对象只有一个lock (机锁)与之相关联.
当 synchronized 被当作函数修饰符的时候, 她所取得的lock 将被交给函数
调用者(某对象), 如果synchronized 用于 Object reference, 则取得的 lock 将被
交给该reference 所指的对象.
对于同一个对象进行同步控制意味着: [调用函数] 的线程将会取得对象的
lock. 持有 [对象A 的lock] 意味着另一个通过 synchronized 函数或synchronized
语句来申请 [对象A的lock]的线程, 在该 lock 被释放之前将无法获得满足.
synchronized 方法或 synchronized 区段内的代码在同一时刻下可由多个线程
执行 ----- 只要是对不同的对象调用该函数.
Ex:
class Foo extends Thread{
private int val;
public Foo(int v){val = v;}
public synchronized void printVal(int v){
while(true){System.out.println(v); }
}
public void run(){printVal(val); }
}
class Bar extends Thread{
private Foo sameFoo;
public Bar(Foo f){ sameFoo = f; }
public void run(){sameFoo.printVal(2); }
}
class PP{
public static void main(String []args){
Foo f1 = new Foo(1);
f1.start();
Bar b = new Bar(f1);
b.start();
Foo f2 = new Foo(3);
f2.start();
}
}
在实例中, 首先create Foo 对象, 此线程进入一个无限循环因此Foo 对象的lock
永远得不到释放; 然后create Bar对象, 此线程对同一个 Foo对象调用同一个
synchronized printVal()方法, 此时这个调用发生阻塞(block), 直到前一次执行结
束. ----- 所以在输出结果中是不可能出现 "2 " 的.
PS: 同步机制(synchronized) 锁定的是对象, 而不是函数或代码. 函数或代码区段
被声明为synchronized 并非意味着她在同一时刻只能由一个线程执行.
Java 不允许将construct Method 声明为synchronized, 原因是两个线程并发调
用同一个construct Method时,她们各自操控的是同一个class 的两个不同
实体的内存. 然而如果在construct 内含了彼此竞争共享资源的代码, 则
必须同步控制那些资源以回避冲突.
47> 弄清楚 synchronized statics 函数与 synchronized instance函数间的差异
同步控制中的 instance函数 / static 函数 / objects / class literals
情况下得到的 locks不同, 因此在决定互斥 (mutual exclusion)行为时一定
要小心谨慎.
48> 以 [private 数据 + 相应的访问函数(accessor) 替换 [public/protected数据]
使用synchronized 函数编码, 目的在于使数据免遭混乱之灾. 为了适当保护数据,
你必须确保正确的声明和访问她们. 这一点很重要.
要想完全保护 synchronized 函数中的数据, 必须令这些数据成为class 的private
成员. 这是唯一可行的办法.
50> 访问共享变量时请使用 synchronized 或 volatile
51> 在单一操作(single Operation) 中锁定所有用到的对象