设计模式Java实现之单例模式
饿汉式
package 单例模式;
/*
* 步骤
* 1.构造器私有化(防止new 对象)
* 2.类的内部创建对象
* 3.向外暴露一个静态的公共方法
* 4.代码实现
* 优缺点分析
* 优点:不用考虑现成的安全问题
* 缺点:一开始就创建了,如果没有使用此对象将会造成内存空间的浪费
*/
public class 饿汉式 {
public static void main(String[] args) {
Single s1=Single.getInstance();
Single s2=Single.getInstance();
//判断是否是同一个对象
System.out.println(s1==s2);
//使用哈希值判断
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s1.hashCode()==s2.hashCode());
System.out.println("************");
Sing s3=Sing.getInstance();
Sing s4=Sing.getInstance();
//判断是否是同一个对象
System.out.println(s3==s4);
//使用哈希值判断
System.out.println(s3.hashCode());
System.out.println(s4.hashCode());
System.out.println(s3.hashCode()==s4.hashCode());
}
}
//饿汉式(静态变量)
class Single{
//私有化构造器防止外部进行new创建对象
private Single() {
}
//内部创建一个对象实例
private final static Single single=new Single();
//创建一个公共方法返回实例对象
public static Single getInstance() {
return single;
}
}
//饿汉式(静态代码块)
class Sing {
//1.私有化构造函数,防止外部使用new创建对象实例
private Sing() {
}
private static Sing sing;
//使用静态代码块
static {
sing=new Sing();
}
//创建公共方法返回实例对象
public static Sing getInstance() {
return sing;
}
}
静态内部类
package 单例模式;
public class 静态内部类 {
public static void main(String[] args) {
singlefo sing1=singlefo. getInstance();
singlefo sing2=singlefo.getInstance();
System.out.println(sing1==sing2);
}
}
//优缺点分析
/*
* 1.这种方式采用了类装在机制来保证初始化实例时只有一个线程
* 2.静态内部类方式在singlefo类被装载时并不会立即实例化,而是在需要实例化时调用getInstance方法,才会装载内部类,从而完成实例化
* 3.类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,再类进行初始化时,别的线程是无法进入的
* 4.优点:避免了线程不安全,利用静态内部类特点是先延迟加载,效率高,推荐使用
*
*/
class singlefo{
//私有化构造器
private singlefo() {
}
//创建内部类
private static class singlein{
//实例化单例对象(成员变量)
private final static singlefo sin=new singlefo();
}
//创建公共的返回实例化对象后的方法
public static synchronized singlefo getInstance() {
return singlein.sin ;
}
}```
懒汉式
package 单例模式;
public class 懒汉式 {
public static void main(String[] args) {
Singlef sing1=Singlef.getInstance();
Singlef sing2=Singlef.getInstance();
System.out.println(sing1==sing2);
}
}
//1.线程不安全的写法
//优缺点说明
/*
-
1.起到Lazy loading的效果,但是只能在单线程下使用
-
2.如果在多线程的情况下,一个线程进入了if语句,还未来得及往下执行,另一个线程也通过了这个判断语句,这个时候便会产生多个实例,所以在多线程环境下不可以使用这种方式
-
结论:在实际开发中,不要使用这种方式(有潜在风险)
*/
class Singlef{
private Singlef() {}
private static Singlef single;
//创建一个方法当需要实例化对象时就进行创建
public static Singlef getInstance() {
//判断该实例对象是否是空,如果是空就就行创建
if(single==null) {
single=new Singlef();
}
return single;
}
}
//2.线程安全的写法(同步方法)
/*优缺点分析
-
1.解决了线程不安全问题
-
2.效率太低了,每个线程在想获得类的实例时,执行getInstance()方法都要进行同步,而其实这个方法只执行一次实例化代码就够了,后面的想获得该实例直接return即可,方法进行同步效率太低
-
结论:在实际开发中,不推荐使用这种方式
*/
class Singles{
private Singles() {}
private static Singles singles;
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
public static synchronized Singles getInstance() {
//判断该实例对象是否是空,如果是空就就行创建
if(singles==null) {
singles=new Singles();
}
return singles;
}
}
枚举方式
package 单例模式;
public class 枚举方式 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//检验
singleen en1=singleen.instance ;
singleen en2=singleen.instance ;
System.out.println(en1==en2);
}
}
//枚举方式
/*
- 优缺点分析:
- 1.使用枚举实现单例模式,不仅能够避免多线程同步问题,而且还可以防止反序列化重新创建新对象
- 2.推荐使用
*/
enum singleen{
instance;
public void printsome() {
System.out.println(“OKK”);
}
}
双重检查
package 单例模式;
public class 双重检查 {
public static void main(String[] args) {
singleton sin1=singleton.getInstance();
singleton sin2=singleton.getInstance();
System.out.println(sin1==sin2);
}
}
//优缺点说明
/*
- 1.Double-Check概念是多线程开发中经常使用到的,进行了两次if的检查,可保证线程的安全
- 2.实例化代码只执行一次,后面再次访问时,判断if直接return实例化对象,避免反复进行方法同步
- 3.线程安全,延迟加载,效率较高,在实际开发中推荐使用这种方法
*/
class singleton{
private singleton() {
}
private static volatile singleton sing;
public static singleton getInstance() {
if(sing==null) {
synchronized (singleton.class ) {
if(sing==null) {
sing=new singleton();
}
}
}
return sing;
}
}