1.单例模式
让一些特定的类在整个程序中只有一个实例(对象)(只能new一次)
2.饿汉模式
即使不去使用这个对象,也会将这个对象给创建好
看以下代码:
//饿汉模式
class Singleton{
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
public class demo1 {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
Singleton s3 = new Singleton();
System.out.println(s1==s2);
System.out.println(s1==s3);
}
}
所以此时需要做出一个限制,禁止别人去new这个实例!!!
//饿汉模式
class Singleton{
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
//做出一个限制,禁止别人去new这个实例!!!
private Singleton(){}
}
public class demo1 {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
//Singleton s3 = new Singleton();
System.out.println(s1==s2);
}
}
此时代码就会出现错误:
设置成private,外面就一定调用不了嘛?
- 使用反射,可以在当前单例模式中,创建出多个实例
- 但是反射是属于"非常规"的编程手段,会带来极大的风险,正常开发中,慎重使用
3.懒汉模式
随用随取,只有当外界需要获取这个对象的时候才会创建出来
//懒汉模式
class Singletonlazy{
private static Singletonlazy instance = null;
public static Singletonlazy getInstance(){
if (instance == null) {
instance = new Singletonlazy();
}
return instance;
}
private Singletonlazy(){}
}
public class demo2 {
public static void main(String[] args) {
Singletonlazy s1 = Singletonlazy.getInstance();
Singletonlazy s2 = Singletonlazy.getInstance();
System.out.println(s1 == s2);
// SingletonLazy s3 = new SingletonLazy();
}
}
4.两种模式关于线程安全的比较[面试题]
4.1 饿汉模式
4.2 懒汉模式
4.2.1 synchronized操作
问:
第二次new操作,不就把原来instance的引用给修改了嘛,之前new出现的对象会立即被回收,那么最后不还是只剩下一个对象了么??
new一个对象,开销可能会非常大!!!
所以此处进行加锁操作:
当然,加锁是一个成本比较高的操作,加锁可能会引起阻塞等待,导致程序执行效率受到影响
不能无脑加锁,非必要,不加锁
4.2.2 内存可见性问题
4.2.3 指令重排序
给instance加上volatile之后, 此时针对instance进行的赋值操作,就不会产生指令重排序了,必然按照123的顺序执行.
所以更改后的完整代码如下:
//懒汉模式
class Singletonlazy{
private static volatile Singletonlazy instance = null;
public static Singletonlazy getInstance(){
// instance 如果为 null, 说明是首次调用, 就需要加锁. 如果非 null, 就说明是后续调用, 就不用加锁了.
if (instance == null) {
synchronized (Singletonlazy.class) {
if (instance == null) {
instance = new Singletonlazy();
}
}
}
return instance;
}
private Singletonlazy(){}
}
public class demo2 {
public static void main(String[] args) {
Singletonlazy s1 = Singletonlazy.getInstance();
Singletonlazy s2 = Singletonlazy.getInstance();
System.out.println(s1 == s2);
// SingletonLazy s3 = new SingletonLazy();
}
}
4.3 总结
饿汉模式:线程更安全
懒汉模式:如果不加处理,线程是不安全的,但是它的效率更高