单例设计模式就是要保证单个类的对象在内存中的唯一性。外部不能new单例设计的 类对象,所以必须私有其构造方法。

  1. 保证唯一性,构造方法只能私有
  2. 构造私有,外部无法建立对象,所以只能内部new对象
  3. 为了拿到对象,接着只能建立静态方法(外部没有办法new对象,所以只能类名调用静态方法),返回内部对象
  4. 又因为__静态不能访问非静态__,所以内部对象也只能是静态的

单例设计模式也叫饿汉,除此之外还有一种叫懒汉(内部对象的延迟加载,线程不安全),详情见代码

demo:

package single;
/*
 * 单利设计模式,保证对象在内存中的唯一性
 * 
 * 1.保证唯一性,构造方法只能私有
 * 2.构造私有,外部无法建立对象
 * 3.只能内部new对象出来
 * 4.为了拿到对象,接着只能建立静态方法,返回内部对象
 * 5.静态不能访问非静态,所以内部对象也只能是静态的
 * 
 * 懒汉式线程不安全
 * 
 * java内的Runtime也是单例设计模式
 */
public class SingleTest {
	public static void main(String[] args) {
		
		/*
		 * 单例(饿汉式)
		 */
		//外部无论如何获取,都只能拿到一个对象
		Single s = Single.getInstance();
		System.out.println(s);
		
		Single s1 = Single.getInstance();
		System.out.println(s1);
		
		/*
		 * 单例(懒汉式)
		 */
		SingleL sL = SingleL.getInstance();
		System.out.println(sL);
		
		SingleL sL1 = SingleL.getInstance();
		System.out.println(sL1);
	}
}

//单例类(饿汉式)
class Single{
	private static Single s = new Single();
	
	private Single(){}
	
	public static Single getInstance(){
		return s;
	}
}
//单例类(懒汉式) 延迟加载 ,线程不安全
class SingleL{
	private static  SingleL s = null;
	
	private SingleL(){}
	
	public static SingleL getInstance(){
		if(s == null)
			s = new SingleL();
		return s;
	}
}

java内也有单例设计模式的类对象:Runtime类,源码如下(JAVA 1.8)

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}
  ...
}

上文提到了懒汉模式(延迟加载)是有线程安全问题的。下面就解释为什么在多线程下会出现不安全的情况,怎么来解决这个问题。

原因: 出现不安全的因素其实很简单,因为多线程下会并发的访问getInstance方法,有可能一个进程执行到if(s == null)这个逻辑代码块中,此时线程跳走了,但是对象还没new出来。,另一个进程又加载运行了此方法。接着原来的那个进程执行完剩下的代码。这样就new了两次对象,导致出现了多个单例对象的实例,产生了不安全的因素。

那如何来解决呢,具体方法请看下面的示例代码。 code:

package thread;

/*
 * 懒汉的多线程安全问题解决
 */
public class ThreadDemo3 {
	public static void main(String[] args) {

		// 建立多线程,来运行
		SingleThread s = new SingleThread();

		/*
		 * 结果出现了两个懒汉的实例
		 *
		 * thread.Single2@6b2ce86d 
		 * thread.Single2@719e4b38
		 * 
		 * 解决办法: 将getInstace的方法变为同步方法,或者加同步代码块
		 */
		new Thread(s).start();
		new Thread(s).start();

	}
}

// 来一个懒汉类
class Single2 {
	private static Single2 s = null;

	private Single2() {
	}

	public static Single2 getInstance() {
		// 静态方法,锁上class
		// 双重if,避免不必要的进入同步代码块,提高效率
		if (s == null) {
			synchronized (Single2.class) {
				if (s == null)
					s = new Single2();
			}
		}
		return s;
	}
}

// 来一个Runnable的子类来玩懒汉
class SingleThread implements Runnable {
	public void run() {
		for (int i = 0; i < 20; i++) {
			Single2 s2 = Single2.getInstance();
			System.out.println(s2);
		}
	}
}