同步关键字synchronized
在 java 中可以通过 synchronized 关键字来支持线程间的同步操作。
synchronized关键字最常见的用法是保护一段代码,如下所示
class Foo implments Runable
{
private String mLock;
public synchronized void lockMethod(){
...
synchronized(mLock){...}
}
...
}
synchronized关键字还可以用在类的方法前面,如下所示
class FooA implments Runable
{
public synchronized void lockMethod(){...}
public synchronized void unLockMethod(){...}
}
synchroinzed的第三种用法是修饰一个静态方法
class FooB implments Runable
{
public synchronized static void lockMethod(){...}
}
三种方法的含义差别还是比较大的。首先要理解是synchronize锁住的是对象,而不是一段代码,在Java中每个对象都可以是一把锁。
首先说第一种方式使用synchronized保护代码块,这种方式适合于单例模式的对象,因为同一个对象中只有一个锁,所以在多个线程中同一时刻调用同一个对象的lockMethod会起到互斥作用。相反的一种情况是,假如Foo类有两个对象foo1、foo2,在两个线程中分别调用foo1的lockMethod和foo2的lockMethod这样是不会起到互斥,原因是对于前者上锁的对象是foo1.mLock,后者是上锁的对象是foo2.mLock,他们其实是不同的锁。
第二种方式利用synchronized修饰非静态方法,语法上等价于下面的写法
synchronized(this){......}
它表明上锁的对象是类的实例对象本身,而第一种方式上锁的对象是实例对象的成员变量,锁的范围变扩大了。这样的结果是,确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁)。当然如果是两个对象分别调用他的函数是不会互斥的。
第三种方式用synchronized修饰一个静态方法,语法上等价于
synchronize(FooB.clss){......}
表明上锁的对象是类本身,这样锁的范围就更大了。导致的结果是同一时刻调用任何FooB实例的lockMethod方法都会互斥,这种方式导致的结果是最严厉的。