Synchronized 锁定的是对象而非函数或代码。
每个Object都有一把锁(Lock),当进行到Synchronized语句或函数的时候,这把锁就会被当前的线程(thread)拿走,其他的(thread)再去访问的时候拿不到锁就被暂停了。
只有当Synchronized的是同一个对象的才是线程安全的(thread-safe)
class Test{
public Synchronized void method1(){ //锁住的对象是this 即当前对象
//........
}
public void method2(){ // 锁住的对象是this 所以和method1是等同的,
//他们之间也是线程安全的。
Synchronized(this){
//................
}
}
public Synchronized static void method3(){ //锁住的对象是Test.class,注:
//Test.class 在虚拟机中只可能有一个,但是Test长生的对象
//可以有多个,因为method3和method1,method2锁住的
//不同,所以他们之间不同步,不是线程安全的。
}
public void method4(){ //跟method3是相同的效果。
Synchronized(Test.class){
//............
}
}
}
这是Synchronized static 函数与Synchronized instance函数之间的区别。
-----------------------------------------
class Test implements Runnable{
private int[] intArray = new int[10]
public synchronized void addToArray(int[] ar){
// modify the intArray
}
public synchronized void subArray(int[] ary){
// modify the intArray
}
public int[] getIntArray(){
return intArray;
}
}
很多人看到上面这个例子马上可以断定这个Test一定是同步的。其实不然,因为他暴露了intArray给外界,所以可以不通过上面两个方法去修改intArray这个filed,假如intArray是public protected数据那就更不行了。那我要访问这个intArray怎么办,那就只好clone一个intArray了。
public int[] getIntArray(){
return intArray.clone();
}
-------------------------------------------
private byte[] lock = new byte[0];//建议用使用这样的lock,因为这个不任何对象都经济。
创建一个元素个数为0的array,并不象创建对象那样需要调用构造函数,所以速度会快些,此外,内含元素的byte arrays往往在jvm中有着比int arrays 更紧凑的表述形式。
---------------------------------------------
long clocktime = 123123.1;
很多人看到上面这个操作的时候肯定会以为这个一定是安全的,因为会认为这是个原子操作。呵呵 错了!
long 数据一般采用64bit(跨越两个32bit word)表述。或许某些jvm实现产品将64-bit操作视为不可分割的(atomic),但现今大部分jvm实现产品都不这样。而是将它视为两个独立的32-bit操作。所以有可能发生旧值的前32bit以及其新值的后32bit组成。这个返回值是错误的。这是因为,面对64bit数据,jvm必须执行一次以上的读写动作。先前讨论的“私有专用副本”与“主内存”也是这个问题。想要改正这个问题,有两个选择:同步控制对clocktime变量的访问,或是将它声明为volatile。