单例模式讲解应用

单线程单例模式

public class Singleton {

        //定义一个属性,用来保存Singleton类对象的实例
        private static Singleton instance;

        //私有构造器,该类不能被外部类使用new方式实例化
        private Singleton(){

        }

        //外部通过该方法获取Singleton类的唯一实例
        public static Singleton getInstance(){
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

此单例模式为非线程安全的,如果两个线程同时调用getInstance方法,很有可能第一个线程刚进入
if(instance == null){}判断内部但是还没有new出实例,第二线程也进去所以创建多个实例。

java多线程程序,线程执行顺序是不确定的,所以在同时多个线程调用Singleton.getInstance()方法时,
存在创建多个实例的可能,会引起程序执行错误。那我们该如何实现多线程下安全的创建一个唯一的实例呢?
锁,加锁。在线程调用Singleton.getInstance()方法时,判断instance == null ? 是,加锁,
其他线程这时只能等待这个线程释放锁,才能进入临界区。那如何加锁,可以使用synchronized。
  public static Singleton getInstance() {
            //synchronized加锁同步会降低效率,这里先判断是否为空
            //不为空则不需要加锁,提高程序效率
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }

单例模式优点

1 在内存中只有一个对象,节省内存空间。
2 避免频繁的创建销毁对象,可以提高性能。
3 避免对共享资源的多重占用。
4 可以全局访问。

适用场景

1 需要频繁实例化然后销毁的对象。
2 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3 有状态的工具类对象。
4 频繁访问数据库或文件的对象。
5 以及其他我没用过的所有要求只有一个对象的场景。
下面举个android中数据库的例子
    SQLiteOpenHelper采用单例模式:
    public class SQLHelper extends SQLiteOpenHelper{
    public static String DB_NAME = "note.db";
    public static int VERSION = 1;
    private static SQLHelper instance;

    public static SQLHelper getInstance(Context context){
        if(instance == null){
            instance = new SQLHelper(context.getApplicationContext());
        }
        return instance;
    }

    private SQLHelper(Context context){
        super(context,DB_NAME,null,VERSION);
        //this.context = context;
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        NoteDao.createTable(db);

    }



    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

}









public class NoteDao {
    public static String TABLE_NAME = "note";
    public static String COLUMN_DATETIME = "datetime";
    public static String COLUMN_CONTENT = "content";
    public static String COLUMN_ID = "id";
    public static String COLUMN_TAG = "tag";
    public static String NOTE_TABLE_CREATE = "create table if not exists "
            +TABLE_NAME +" ("
            +COLUMN_ID +" INTEGER PRIMARY KEY AUTOINCREMENT, "
            +COLUMN_DATETIME+" TEXT,"
            +COLUMN_CONTENT+" TEXT,"
            +COLUMN_TAG +" TEXT"+")";

      static String[] str_column = {COLUMN_DATETIME,COLUMN_CONTENT,COLUMN_TAG};
      static String[] int_cloumn = {COLUMN_ID};

    public static void createTable(SQLiteDatabase db){
        db.execSQL(NOTE_TABLE_CREATE);
    }
    public static void dropTable(SQLiteDatabase db) {
        String sql = "DROP TABLE " +  "IF EXISTS "  + " note";
        db.execSQL(sql);
    }

    private SQLHelper helper;

    public NoteDao(Context context){
        helper = SQLHelper.getInstance(context);
    }


      //插入数据
    public boolean insertBean(NoteBean bean){
        boolean flag = false;
        SQLiteDatabase database = null;
        long id = -1;
        try{
            database = helper.getWritableDatabase();
            ContentValues values = getContentValues(bean);
            String tableName = TABLE_NAME;
            id = database.insert(tableName,null,values);
            flag = (id !=-1?true:false);
            if(database != null){
                database.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        Log.e("gac","insertbean flag:"+flag);
        return flag;
    }

}


执行插入数据的操作 只需要执行new NoteDao(Context).insertBean方法 可以避免创建过多的SqliteHelper对象
### 设计模式的详细讲解 #### 什么是设计模式? 设计模式是一种创建型设计模式,它确保某一个类只有一个实存在,并提供一个全局访问点来获取这个唯一的实[^2]。 #### 设计模式的核心特点 1. **唯一性**:在整个应用程序生命周期中,某个类始终只会有一个实。 2. **全局访问**:可以通过统一的方式访问到该唯一实。 3. **延迟加载(可选)**:某些实现方式支持在第一次使用时才创建实,而不是一开始就创建。 --- #### 设计模式的应用场景 以下是常见的单例模式应用场景: 1. 需要管理共享资源的情况,如线程池、缓存、日志记录器等。 2. 数据库连接池的设计,避免频繁创建销毁数据库连接造成的性能开销。 3. 工具类的设计,尤其是那些不需要维护状态的功能性工具类。 4. 应用程序配置文件读取模块,保证配置的一致性和高效性[^2]。 --- #### 设计模式的优点 1. **节约系统资源**:通过保证一实的存在,减少不必要的内存占用和计算成本。 2. **简化通信机制**:由于对象可以在不同部分之间共享数据,因此可以方便地协调这些组件之间的交互。 3. **增强可控性**:相比于普通的全局变量,单例模式提供了更严格的控制手段,防止意外修改或覆盖[^3]。 --- #### 常见的单例模式实现方式 ##### 1. 饿汉式(Eager Initialization) 饿汉式的单例模式会在类加载阶段就立即创建好实,适合于简场景下使用。 ```java public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 这种方式具有以下特性: - 实现简直观; - 不需要额外处理多线程安全问题,天然线程安全[^4]。 --- ##### 2. 懒汉式(Lazy Initialization) 懒汉式仅在首次调用 `getInstance` 方法时才会创建实,适用于需要延迟加载的情形。 ```java public class Singleton { private static Singleton instance; private Singleton() {} public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 此版本虽然解决了按需加载的问题,但由于每次调用都需要同步锁操作,可能导致性能下降。优化后的双重校验锁定如下: ```java public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // 创建实 } } } return instance; } } ``` 这里引入了 `volatile` 关键字以确保可见性和指令重排序的安全性。 --- ##### 3. 枚举(Enum Singleton) 利用 Java 的枚举语法实现单例模式被认为是最简洁且最安全的方法之一。 ```java public enum Singleton { INSTANCE; public void doSomething() { System.out.println("Doing something..."); } } ``` 优点包括但不限于: - 自动抵御反射攻击; - 天然支持序列化/反序列化的安全性; - 简洁明了,推荐作为首选方案。 --- #### 设计模式需要注意的地方 尽管单例模式非常有用,但在实际开发过程中仍有一些潜在的风险需要注意: 1. **过度滥用**:如果过多依赖单例模式,则会使得代码结构变得僵硬难以测试和扩展。 2. **多线程环境下的竞争条件**:如果不采取适当措施保障线程安全的话,可能会引发竞态条件等问题。 3. **跨 JVM 场景失效**:在一个分布式环境中运行多个独立进程的情况下,即使采用了单例模式也不能保证绝对意义上的“唯一”。 --- #### 总结 综上所述,设计模式作为一种经典的设计理念,在软件工程领域占据重要地位。无论是为了节省资源还是加强全局一致性考量,合理运用这一技术都能够带来显著收益。然而与此同时也要警惕其局限所在,权衡利弊之后再决定是否采用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值