synchronized与lock:
1. synchronized是java内置关键字,在jvm层面,Lock是个java类;
2. synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3. synchronized会自动释放锁(线程执行完同步代码会释放锁,线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成死锁;
4. 用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2 等待。如果线程1阻塞,线程2则会一直等待下去,而Lock就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.Synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可),Lock锁适合大量同步的代码的同步问题,synchronized锁适合少量的同步问题。
单例模式,是一个非常重要的一个设计模式,大多数程序员都可以很轻易的写出来,但是想要写出一个完美的单例模式却不简单。并发问题是需要考虑到的,一旦没做好并发控制,就有可能产生多个实例,从而破坏的单例。Java中,synchronized和lock等是最常见的并发控制。下面是几个单例模式的实现:
枚举:
-
public enum Singleton {
-
INSTANCE;
-
public void whateverMethod() {
-
}
-
}
静态内部类:
-
public class Singleton {
-
private static class SingletonHolder {
-
private static final Singleton INSTANCE = new Singleton();
-
}
-
private Singleton (){}
-
public static final Singleton getInstance() {
-
return SingletonHolder.INSTANCE;
-
}
-
}
饿汉:
-
public class Singleton {
-
private static Singleton instance = new Singleton();
-
private Singleton (){}
-
public static Singleton getInstance() {
-
return instance;
-
}
-
}
饿汉变种:
-
public class Singleton {
-
private static class SingletonHolder {
-
private static final Singleton INSTANCE = new Singleton();
-
}
-
private Singleton (){}
-
public static final Singleton getInstance() {
-
return SingletonHolder.INSTANCE;
-
}
-
}
相信有经验的行家都可以看出来,以上几种方法,虽然没有在代码中显示的使用synchronized,但是,都是借助了ClassLoader的线程安全机制。而ClassLoader的线程安全机制底层也是使用了synchronized的。其中两个“饿汉”,其实是通过定义静态成员变量,以保证instance可以在类初始化的时候被实例化,类的初始化是由ClassLoader完成的,这其实就是利用了ClassLoader的线程安全机制。
对于静态内部类,这种方式是Singleton类被装载了,instance不一定被初始化,做法上相对于两种饿汉方式稍微优化了一点,因为SingletonHolder类没有被主动使用,只有通过调用getInstance方法时,擦爱会装载SingletonHolder类,从而实例化instance,原理和饿汉是一样的。如果把枚举类进行反序列化,你也会发现他也是使用了static final来修饰每一个枚举项。
如何不使用synchronized和lock来实现线程安全的单例?答案是CAS,很多乐观锁都是基于CAS实现的,CAS不适使用传统的锁机制来保证线程安全的,是一种基于忙等待的算法,依赖底层硬件,可以支持较大的并行度,但是有一个重要的缺点,如果忙等待一直执行不成功,会对CPU造成较大的执行开销,而且这种写法如果有多个线程同时执行singleton = new Singleton();也会比较浪费堆内存,借助CAS实现的单例模式:
-
public class Singleton {
-
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();
-
-
private Singleton() {}
-
-
public static Singleton getInstance() {
-
for (;;) {
-
Singleton singleton = INSTANCE.get();
-
if (null != singleton) {
-
return singleton;
-
}
-
-
singleton = new Singleton();
-
if (INSTANCE.compareAndSet(null, singleton)) {
-
return singleton;
-
}
-
}
-
}
-
}
阅读(3072) | 评论(0) | 转发(0) |