Talk is cheap Show me the code
个人学习笔记--仅供参考
单例模式可以保证内存里只有一个实例,减少了内存开销;可以避免对资源的多重占用。
单例模式看起来非常简单,实现起来其实也非常简单。
总结一下,
前几章主要讲了
饿汉式:
1,经典饿汉式 2静态代码块饿汉式
优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。
缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅
懒汉式
1,普通懒汉式 :线程不安全
2, 两种加锁懒汉式,互斥锁解决线程安全,synchronized,容易阻塞
3. 双重检查锁,即利用volatile 和 synchronized 关键字,保证可见性和原子性,降低阻塞
其他式
1,,静态内部类方式 ,去除了锁,线程也是安全的
2.枚举式 JDK 底层 ,只有一个protected构造方法 ,枚举式单例也是《Effective
Java》书中推荐的一种单例实现写法。在JDK 枚举的语法特殊性,以及反射也为枚举保
驾护航,让枚举式单例成为一种比较优雅的实现。
3.注册式 非线程安全
这些看起开都解决了单例,时间上,通过java 反射机制,序列化和反序列化,都可以破坏。
所以解决方案:
1.不要实现Serializable接口,如果有Serializable ,可以利用构造一个自己的readResolve() 屏蔽新生成的对象
彩蛋:Serializable,生成新对象是从内存中直接拷贝的,不会调用new方法,也叫深度拷贝,
2.反射只需要再构造方法中,判断返回的实例是不是空的,只允许非空下返回
再由此发散
研究下ThreadLocal
ThreadLocal 不能保证其
创建的对象是全局唯一,但是能保证在单个线程中是唯一的,天生的线程安全
package pattern;
public class ThreadLocalSingleton {
private ThreadLocalSingleton() {}
private static final ThreadLocal<ThreadLocalSingleton>
tl= new ThreadLocal<ThreadLocalSingleton>() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
public static ThreadLocalSingleton getInstance() {
return tl.get();
}
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ThreadLocalSingleton h1 = ThreadLocalSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + h1);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
ThreadLocalSingleton h2 = ThreadLocalSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + h2);
}
});
t1.start();
t2.start();
System.out.println("End");
}
}
结果
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
End
Thread-1:pattern.ThreadLocalSingleton@28d0be7
Thread-0:pattern.ThreadLocalSingleton@17135162
我们发现,在主线程main 中无论调用多少次,获取到的实例都是同一个,都在两个子线
程中分别获取到了不同的实例。那么ThreadLocal 是如果实现这样的效果的呢?我们知
道上面的单例模式为了达到线程安全的目的,给方法上锁,以时间换空间。ThreadLocal
将所有的对象全部放在ThreadLocalMap 中,为每个线程都提供一个对象,实际上是以
空间换时间来实现线程间隔离的。