JAVA中synchronized关键字能够作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。假如再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。synchronized
void
f() {
/* body */ }
和void f() { synchronized(this) { /* body */
} }
是完全等价的。
synchronized(class)很特别,它会让另一个线程在任何需要获取class做为monitor的地方等待。class与this作为不同的监视器可以同时使用,不存在一个线程获取了class,另一个线程就不能获取该class的一切实例。
- 对于实例同步方法,锁是当前实例对象。
- 对于静态同步方法,锁是当前对象的Class对象。
- 对于同步方法块,锁是Synchonized括号里配置的对象。
synchronized(class)
synchronized(this)
线程各自获取monitor,不会有等待。
synchronized(this)synchronized(this)
如果不同线程监视同一个实例对象,就会等待;如果不同的实例,不会等待。
synchronized(class)synchronized(class)
如果不同线程监视同一个实例或者不同的实例对象,都会等待。
单例模式,有“懒汉式”和“饿汉式”两种。
懒汉式
单例类的实例在第一次被引用时候才被初始化。
public class Singleton { private static Singleton instance=null; private Singleton() { } public static Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式
单例类的实例在加载的时候就被初始化。
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance(){ return instance; } }
在单线程程序中,上面两种形式基本可以满足要求了,但是在多线程环境下,单例类就有可能会失效,这个时候就要对其加锁了,来确保线程安全。
对线程加锁用的synchronized关键字,这个关键字的用法主要也分为两种:
一种是加在方法名之前,形如:synchronized methodeName(params){……};
二是声明同步块,形如:synchronized(this){……};
下面是对懒汉式单例类加上线程同步的实现:
同步方法:
public class Singleton { private static Singleton instance=null; private Singleton() { } public synchronized static Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
这种方式效率比较低,性能不是太好,不过也可以用,因为是对整个方法加上了线程同步,其实只要在new的时候考虑线程同步就行了,这种方法不推荐使用。
同步代码块:
public class Singleton { private static Singleton instance; private final static Object syncLock = new Object(); private Singleton() { } public static Singleton getInstance(){ if (instance == null) { synchronized (syncLock) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
synchronized同步块括号中的锁定对象是采用的一个无关的Object类实例,而不是采用this,因为getInstance是一个静态方法,在它内部不能使用未静态的或者未实例的类对象,因此也可以用下面的方法来实现:
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance(){ if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
同步代码块的这两种方式都是比较推荐使用的,我就一直在项目中使用,有问题以后可以再改进。