1、单例模式

要解决的问题:

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。

具体代码的实现

饿汉式1

class Bank{    
     //1.私化类的构造器
     private Bank(){     
     }
     //2.内部创建类的对象
     //4.要求此对象也必须声明为静态的
     private static Bank instance = new Bank();
     //3.提供公共的静态的方法,返回类的对象
     public static Bank getInstance(){
          return instance;
     }
}

饿汉式2

使用了静态代码块

class Order{     
     //1.私化类的构造器
     private Order(){          
     }     
     //2.声明当前类对象,没初始化
     //4.此对象也必须声明为static的
     private static Order instance = null;
     static{
          instance = new Order();
     }
     //3.声明public、static的返回当前类对象的方法
     public static Order getInstance(){
          return instance;
     }  
}

懒汉式

class Order{    
     //1.私化类的构造器
     private Order(){          
     }     
     //2.声明当前类对象,没初始化
     //4.此对象也必须声明为static的
     private static Order instance;     
     //3.声明public、static的返回当前类对象的方法
     public static Order getInstance(){       
          if(instance == null){          
              instance = new Order();    
          }
          return instance;
     }    
}

对比

线程安全的懒汉

//由于直接在方法上添加synchronized,开销比较大,所以使用双重检查锁
public class Singlet(){
    private volatile static Singlet singlet;
    private Singlet(){};
    public static Singlet getSinglet(){
        if(singlet == null){
            synchronized(Singlet.class){
                if(singlet == null){
                    singlet = new Singlet();
                }
            }
        }  
    }
}

volatile关键字

volatile可以保存内存可见,即便是跨线程,还可以禁止指令重排

例如,此时程序会死循环,因为,主线程在运行到while循环的时候,i为0,而且这个i内存是不可见的,所以,即使另一个线程改变了i的值,循环还会继续

public class Test2 {
    private int i = 0;
    public static void main(String[] args) {
        Test2 test2 = new Test2();

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                test2.add();
                System.out.println(test2.i);
            }
        });
        thread.start();

        while(test2.i == 0){

        }
        System.out.println("end---");
    }

    public void add(){
        i = 100;
    }
}

如果对i加上volatile关键字,那么内存可见,就不会出现死循环了

public class Test2 {
	private volatile int i = 0;
	public static void main(String[] args) {
		Test2 test2 = new Test2();
		
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				test2.add();
				System.out.println(test2.i);
			}
		});
		thread.start();
		
		while(test2.i == 0){
			
		}
		System.out.println("end---");
	}
	
	public void add(){
		i = 100;
	}
}