一:单例模式的概述
1.概念:单例模式的概念就是有时需要一个类来只保留一个对象并且不希望有更多的对象就叫做单例模式
2.单例模式的特点
1):单例模式只能有一个实例
2): 单例类必须创建一个自己的实例(唯一的)
3):单例类的必须向其他对象创建这一个唯一实例
3.单例模式与静态类的对比
(1)单例可以继承和被继承,方法可以被重写,但是静态方法就不行了
(2)静态方法的创建的对象在被执行完了之后就会被GC处理不会一直存在于一个内存之中
(3)静态方法在第一次执行的时候需要初始化,但是单例模式可以延迟加载
(4)单例模式可以防止重复创建多个对象造成资源的浪费
二: 单例模式的举例
单例模式有以下几种的创建方式
(1)饿汉模式:在程序启动和或者类加载的过程中对象就已经创建好了
举例:
public class Demo1 {
// private Demo1(){
// }//构造方法私有
private static Demo1 demo1=new Demo1();
public static Demo1 getDemo1(){
return demo1;
}//获取一个对象
public static void main(String args[]) {
for (int i = 0; i <100 ; i++) {
new Thread(()->{
Demo1 demo1 = Demo1.getDemo1();
System.out.println(demo1);
}).start();
}
}
}
由此可见,恶汉模式可以创建一个唯一的实例
饿汉模式在类加载的时候就已经创建了一个自己的唯一的对象,所以饿汉模式天生是安全的
总结:饿汉模式的线程是安全的,在类创建的时候就已经创建了一个对象出来了,但是这个对象会一直存在于内存之中会耗费内存的空间,但是虽然占有了空间但是却因此在调用的时候更快了,因为初始化的工作已经完成。
(2)饱汉模式:
与饿汉模式的区别是它不着急创建一个自己的对象,只有在需要用到创建一个对象的时候才会去判断并且创建,但是当有大量的线程来进行创建的时候就会出现线程的并发问题,会出现创建的多个对象
例如:
public class Student {
private void Student(){
}
private static Student student=null;
public static Student getStudent(){
if(student==null){
student=new Student();
}
return student;
}
}
class test{
public static void main(String args[]){
Thread t1 = new Thread(() -> {
Student student = Student.getStudent();
System.out.println(student);
});
Thread t2 = new Thread(() -> {
Student student = Student.getStudent();
System.out.println(student);
});
Thread t3 = new Thread(() -> {
Student student = Student.getStudent();
System.out.println(student);
});
Thread t4 = new Thread(() -> {
Student student = Student.getStudent();
System.out.println(student);
});
t1.start();
t2.start();
t3.start();
t4.start();
}}
1)双重校验
public class Student {
private void Student(){
}
private static Student student=null;
public static Student getStudent() {
synchronized (Student.class) {//给类加锁,所有的对象均不能同时运行
if (student == null) {
student = new Student();
}
return student;
}
}
}
上面这种每次都需要释放锁加锁,效率低,一般可以写成下面这种
public class Student {
private void Student(){
}
private static Student student=null;
public static Student getStudent() {
//给类加锁,所有的对象均不能同时运行
if (student == null) {
synchronized (Student.class) {
student = new Student();
}
}
return student;
}
}
2)静态内部类的方法
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
3)给获取方法上加锁
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
总结:
饿汉模式的好处:延时加载,只有在用的时候采取创建对象,不占用空间
缺点:需要保证线程同步付出了效率的代价
所以可以这么说:饱汉模式:牺牲了效率换取了空间
饿汉模式是牺牲了空间换取了效率。