学习内容:
1、 单例模式
- 饿汉式
// 单例模式的,饿汉式方式,这种单例模式是可以使用的,但缺点就是可能造成内存的浪费
// 因为有可能创建了这个类,但是在整个项目的运行过程中可能并没有使用到创建的当前对象
class SingleH{
// 1.要实现单例模式,需要设置构造器私有化,禁止外部使用new创建实例对象
private SingleH(){
}
// 2.使用静态方式创建本类内部的对象
private static final SingleH instance = new SingleH();
// 3.提供一个公有的静态方法,返回实例对象
public static SingleH getInstance(){
return instance;
}
}
- 饿汉式(静态实现)
//使用静态代码块的方式实现对象的创建
class SingleHungryS {
// 1.私有化构造方法
private SingleHungryS() {
}
// 2.创建静态变量
private static SingleHungryS instance;
// 使用静态代码块实现对象的创建
static {
instance = new SingleHungryS();
}
// 3.提供一个公有的静态方法,返回实例对象
public static SingleHungryS getInstance() {
return instance;
}
}
- 懒汉式(线程不安全)
// 单例模式:懒汉式(线程不安全),单线程下可以使用,多线程的情况下会出现线程不安全,所以在项目中不推荐使用
class SingleL{
// 1.私有化构造方法
private SingleL(){
}
// 2. 创建变量
private static SingleL instance;
// 3.给当前的静态变量进行赋值并进行返回
public static SingleL getInstance(){
// 先进行判断当前的对象是否存在,如果不存在则进行创建然后再返回对象,否则直接返回
// 在这一步的时候可能会出现线程不安全的情况,假设当前有a,b两个线程都进入这个方法里面,
// 此时a判断没有实例,就会进行创建,与此同时,在创建的时候,b也拿到了,发现也没有实例
// 也会进行创建,那么此时就可能出现线程不安全的问题。
if (instance == null){
instance = new SingleL();
}
return instance;
}
}
- 懒汉式(线程安全,但是效率太低)
// 单例模式:懒汉式(线程安全),单线程下可以使用,多线程的情况下会出现线程安全,
// 但是效率太低,所以在项目中不推荐使用
class SingleL2 {
// 1.私有化构造方法
private SingleL2() {
}
// 2. 创建变量
private static SingleL2 instance;
// 3.给当前的静态变量进行赋值并进行返回
// 加入了同步synchronized实现了线程的同步安全问题,但是效率太低,不推荐使用
// 因为在多线程的情况下,加入a线程拿到了,此时其他的线程就必须在外进行等候a线程
// 执行完毕,才可以执行下一个线程,个人理解就好像是使用队列的操作(个人理解,大佬勿喷),
public static synchronized SingleL2 getInstance() {
// 先进行判断当前的对象是否存在,如果不存在则进行创建然后再返回对象,否则直接返回
if (instance == null) {
instance = new SingleL2();
}
return instance;
}
}
- 懒汉式(双重检查,实际中推荐使用)
// 单例模式的懒加载方式,实现双重检查,并加入了同步机制,保证线程安全,并解决了饿汉式的内存浪费问题,
// 同时又保证了代码的效率问题,项目中推荐使用的方式
class SingleLP {
// 1.私有化构造函数
private SingleLP() {
}
// 2。设置同步变量,此时加入了volatile关键字
private static volatile SingleLP instance;
// 3.对象的构建并返回,使用synchronized实现线程安全的问题,假设来了多个线程,a拿到了线程,
// 加入此时实例为空,那么其他的线程需要在函数外进行等待,a线程将会执行实例的创建工作,a线程
// 执行完毕,其他的线程看到实例不为空就会直接进行返回当前的实例
public static synchronized SingleLP getInstance() {
if (instance == null) {
// synchronized的参数表示对谁进行同步
synchronized (SingleLP.class) {
if (instance == null) {
instance = new SingleLP();
}
}
}
return instance;
}
}
- 静态内部类的方式(推荐使用)
// 单例模式:使用静态类的方式
// 优点:避免了线程不安全的问题,利用静态内部类的特点实现了延迟加载,效率比较高,推荐使用
class SingleLazyPlusS {
// 1.私有化构造函数
private SingleLazyPlusS() {
}
// 2.创建静态内部类(不会随着类的加载而加载),只用执行getInstance()方法的时候才会执行静态内部类的创建
private static class SingleTon {
private static final SingleLazyPlusS INSTANCE = new SingleLazyPlusS();
}
// 3.执行调用实例的方法
public static synchronized SingleLazyPlusS getInstance() {
return SingleTon.INSTANCE;
}
}
- 枚举实现单例模式
public class SingleEnum {
public static void main(String[] args) {
SingleE instance = SingleE.INSTANCE;
SingleE instance1 = SingleE.INSTANCE;
System.out.println("instance.hashCode() = " + instance.hashCode());
System.out.println("instance1.hashCode() = " + instance1.hashCode());
instance.sayOk();
}
}
/**
* 使用的枚举的方式实现单例模式
* 枚举的方式不仅能够避免多线程同步的问题,还可以防止反序列化重新创建新的对象
*/
enum SingleE{
INSTANCE;
public void sayOk(){
System.out.println("ok");
}
}