赞
踩
懒汉模式代码
- package Singleton;
-
-
- public class LazySingleton {
- private static LazySingleton lazySingleton=null;
- private LazySingleton() {
-
- }
- public static LazySingleton getInstance() {
- if(lazySingleton==null)
- lazySingleton=new LazySingleton();
- return lazySingleton;
- }
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
-
- }
-
- }
懒汉模式最主要得就是会在多线程中重复创建 对象实例,若线程较多则会导致内存使用过大,甚至导致程序崩溃。测试代码如下
Test代码:
- package Singleton;
-
- public class Test {
-
- public static void main(String[] args) {
- Thread t1=new Thread(new T(),"Thread_1");
- Thread t2=new Thread(new T(),"Thread_2");
- t1.start();
- t2.start();
- // TODO Auto-generated method stub
-
- }
-
- }
实习Runnable接口代码如下
- package Singleton;
-
-
- public class T implements Runnable {
- public void run() {
- System.out.println(Thread.currentThread().getName()+" "+LazySingleton.getInstance());
- }
- public static void main(String[] args) {
- // TODO Auto-generated method stub
-
- }
-
- }
虽然运行之后,结果输出得 实例 是同一个实例,但是这个结果是不确定得,也有可能会输出多个实例。即便输出同一个对象实例,但是中间会多次创建对象实例,后一个覆盖前一个对象,会造成内存资源的消耗,所以懒汉模式是一种不可取的方式。
解决方法:利用synchronized加到方法上,锁住这个类
- package Singleton;
-
-
- public class LazySingleton {
- private static LazySingleton lazySingleton=null;
- private LazySingleton() {
-
- }
- public synchronized static LazySingleton getInstance() {
- if(lazySingleton==null)
- lazySingleton=new LazySingleton();
- return lazySingleton;
- }
- //下面这个形式和上面的是一样的,都是将这个类加了锁,同一时间只允许一个线程访问这个类
- // public static LazySingleton getInstance() {
- // synchronized(LazySingleton.class) {
- // if(lazySingleton==null)
- // lazySingleton=new LazySingleton();
- // }
- // return lazySingleton;
- // }
-
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
-
- }
-
- }
注意:多线程debug,要切换断点设置为Thread模式下,不能是All模式下,Thread模式下,每个线程的断点都可以真的起到作用,但是All模式下,只能断到主线程的断点。
直接将synchronized加在方法上,开销较大,因此我们使用DoubleCheck方式,代码如下
- package Singleton;
-
- public class LazyDoubleCheckSingleton {
- private static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
- private LazyDoubleCheckSingleton() {
-
- }
- public static LazyDoubleCheckSingleton getInstance() {
- if(lazyDoubleCheckSingleton==null) {
- synchronized (LazyDoubleCheckSingleton.class) {
- if(lazyDoubleCheckSingleton==null)
- lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
- }
- }
- return lazyDoubleCheckSingleton;
- }
-
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
-
- }
-
- }
有了双重检查后,当进入方法,判断lazyDoubleCheckSingleton是否为null,当不为null时,直接返回lazyDoubleCheckSingleton即可,就省去了锁开销。但是仍有隐患,如下图
步骤2 3在单线程中允许重排序,所以出现上图问题。
改进措施(解决重排序):将成员变量lazyDoubleCheckSingleton加上volatile修饰符,使其写操作具有可见性。(volatile的汇编语言多了一些代码,就是在写操作后使这个内存对象的缓存无效,当再需要用时,需要再从系统内存中读到处理器的缓存里,即可见性)
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
基于类初始化的延迟加载:静态内部类
原理:外部类加载时,不一定加载内部类,内部类不加载则不会去初始化instance,故而不占用内存,只有当getInstance()方法第一次被调用时,才会去初始化instance,延迟了单例的实例化,也使得线程安全,代码如下
- package Singleton;
-
- public class StaticInnerClassSingleton {
- private StaticInnerClassSingleton() {
-
- }
- private static class InnerClss{
- private static StaticInnerClassSingleton scs=new StaticInnerClassSingleton();
- }
- public StaticInnerClassSingleton getInstance() {
- return InnerClss.scs;
- }
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
-
- }
-
- }
存在隐患:静态内部类无法传参
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。