java单例设计模式
单例设计模式就是要保证单个类的对象在内存中的唯一性。外部不能new单例设计的 类对象,所以必须私有其构造方法。
- 保证唯一性,构造方法只能私有
- 构造私有,外部无法建立对象,所以只能内部new对象
- 为了拿到对象,接着只能建立静态方法(外部没有办法new对象,所以只能类名调用静态方法),返回内部对象
- 又因为__静态不能访问非静态__,所以内部对象也只能是静态的
单例设计模式也叫饿汉,除此之外还有一种叫懒汉(内部对象的延迟加载,线程不安全),详情见代码
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);
}
}
}