关闭→
当前位置:科普经验站>综合知识>单例怎么写

单例怎么写

科普经验站 人气:1.28W
1. 这个单例的写法跟一般的写法有什么区别

感觉这么写可以防止并发操作导致多次实例化例如以下常规写法:public class Singleton { private Singleton() {} private static Singleton instance = null; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}当并发调用Singleton.getInstance()时,可能会让new Singleton()执行多次;当然改成如下形式也可以避免这种问题:public class Singleton { private Singleton() {} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; }}。

单例怎么写
2. 如何写一个简单的单例模式

一、基本的实现思路:

单例的实现主要是通过以下两个步骤:

1、将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;

2、在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。

二、示范如下:

1、枚举实现单例:

2、懒汉式线程不安全:

3、懒汉式线程安全:

4、饿汉式:

5、双重校验锁:

6、静态内部类:

扩展资料:

一、单列模式简介:

单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义。

二、懒汉与饿汉:

1、懒汉方式:指全局的单例实例在第一次被使用时构建。

2、饿汉方式:指全局的单例实例在类装载时构建。

三、单例模式的三要点:

1、某个类只能有一个实例。

2、它必须自行创建这个实例。

3、它必须自行向整个系统提供这个实例。

四、优缺点:

1、优点:

①实例控制:单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

灵活性:因为类控制了实例化过程,所以类可以灵活更改实例化过程。

2、缺点:

①开销:虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

②可能的开发混淆:使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

③对象生存期:不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

参考资料:百度百科单列模式

3. 单例模式怎么写,求一份饿汉式单例 一份懒汉式单例

//懒汉式

public class A{

public static A a = null;

public A(){

}

public A getInstance(){

if(a==null){

return new A();

}

return a;

}

}

//饿汉式

public class A{

public static synchonized A a = new A();//线程安全

public A(){

}

public A getInstance(){

return a;

}

}

所谓饿就是急,无论需不需要先将单例对象给创建了,而懒汉式就是慢,需要的时候再创建,此外还有利用java缓存式的,利用内部类实现的单例模式,具体可以参考《清华大学出版社》出版的《研磨设计模式》

4. 如何写一个简单的单例模式

单例模式的要点有三个;一是某各类只能有一个实例;二是它必须自行创建这个事例;三是它必须自行向整个系统提供这个实例。

单例模式有以下的特点:

1 单例类只可有一个实例。

2 单例类必须自己创建自己这惟一的实例。

3 单例类必须给所有其他对象提供这一实例。

public class EagerSingleton

{

private static final EagerSingleton m_instance =

new EagerSingleton();

/**

* 私有的默认构造子

*/

private EagerSingleton() { }

/**

* 静态工厂方法

*/

public static EagerSingleton getInstance()

{

return m_instance;

}

}

在这个类被加载时,静态变量m_instance 会被初始化,此时类的私有构造子会被调用。这时候,单例类的惟一实例就被创建出来了。

楼主可以具体参阅 阎宏博士的《Java与模式》一书的第十五章

5. 如何正确地写出单例模式

当被问到要实现一个单例模式时,很多人的第一反应是写出如下的代码,包括教科书上也是这样教我们的。

1234567891011public class Singleton {private static Singleton instance;private Singleton (){}public static Singleton getInstance () {if (instance == null ) {instance = new Singleton();}return instance;}}这段代码简单明了,而且使用了懒加载模式,但是却存在致命的问题。当有多个线程并行调用 getInstance() 的时候,就会创建多个实例。

也就是说在多线程下不能正常工作。懒汉式,线程安全为了解决上面的问题,最简单的方法是将整个 getInstance() 方法设为同步(synchronized)。

123456public static synchronized Singleton getInstance () {if (instance == null ) {instance = new Singleton();}return instance;}虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。因为在任何时候只能有一个线程调用 getInstance() 方法。

但是同步操作只需要在第一次调用时才被需要,即第一次创建单例实例对象时。这就引出了双重检验锁。

双重检验锁双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null ,一次是在同步块外,一次是在同步块内。

为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。12345678910public static Singleton getSingleton () {if (instance == null ) { //Single Checkedsynchronized (Singleton.class) {if (instance == null ) { //Double Checkedinstance = new Singleton();}}}return instance ;}这段代码看起来很完美,很可惜,它是有问题。

主要在于 instance = new Singleton() 这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。给 instance 分配内存调用 Singleton 的构造函数来初始化成员变量将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)但是在 JVM 的即时编译器中存在指令重排序的优化。

也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。

我们只需要将 instance 变量声明成 volatile 就可以了。12345678910111213141516public class Singleton {private volatile static Singleton instance; //声明成 volatileprivate Singleton (){}public static Singleton getSingleton () {if (instance == null ) {synchronized (Singleton.class) {if (instance == null ) {instance = new Singleton();}}}return instance;}}有些人认为使用 volatile 的原因是可见性,也就是可以保证线程在本地不会存有 instance 的副本,每次都是去主内存中读取。

但其实是不对的。使用 volatile 的主要原因是其另一个特性:禁止指令重排序优化。

也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。

从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。但是特别注意在 Java 5 以前的版本使用了 volatile 的双检锁还是有问题的。

其原因是 Java 5 以前的 JMM (Java 内存模型)是存在缺陷的,即时将变量声明成 volatile 也不能完全避免重排序,主要是 volatile 变量前后的代码仍然存在重排序问题。这个 volatile 屏蔽重排序的问题在 Java 5 中才得以修复,所以在这之后才可以放心使用 volatile。

相信你不会喜欢这种复杂又隐含问题的方式,当然我们有更好的实现线程安全的单例模式的办法。饿汉式 static final field这种方法非常简单,因为单例的实例被声明成 static 和 final 变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。

12345678910public class Singleton {//类加载时就初始化private static final Singleton instance = new Singleton();private Singleton (){}public static Singleton getInstance (){return instance;}}这种写法如果完美的话,就没必要在啰嗦那么多双检锁的问题了。缺点是它不是一种懒加载模式(lazy initialization),单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。

饿汉式的创建方式在一些场景中将无法使用:譬如 Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。静态内部类 static nested class我比较倾向于使用静态内部类的方法,这种方法也是《Effective Java》上所推荐的。

123456789public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton (){}public static final Singleton getInstance () {return 。

6. java中怎么写一个单例的例子,看了许多,就是不会写.

单例就是把构造方法私有化,在类里实例化对象,并且给一个共有的能返回这个对象的方法

public class Single{

private Single s = null;

private Single(){

}

public static synchronized Single getS(){

if (s == null) {

s = new Singleton();

}

return s;

}

}

7. 如何正确地写出单例模式

当被问到要实现一个单例模式时,很多人的第一反应是写出如下的代码,包括教科书上也是这样教我们的。

1234567891011public class Singleton {private static Singleton instance;private Singleton (){}public static Singleton getInstance () {if (instance == null ) {instance = new Singleton();}return instance;}}这段代码简单明了,而且使用了懒加载模式,但是却存在致命的问题。当有多个线程并行调用 getInstance() 的时候,就会创建多个实例。

也就是说在多线程下不能正常工作。懒汉式,线程安全为了解决上面的问题,最简单的方法是将整个 getInstance() 方法设为同步(synchronized)。

123456public static synchronized Singleton getInstance () {if (instance == null ) {instance = new Singleton();}return instance;}虽然做到了线程安全,并且解决了多实例的问题,但是它并不高效。因为在任何时候只能有一个线程调用 getInstance() 方法。

但是同步操作只需要在第一次调用时才被需要,即第一次创建单例实例对象时。这就引出了双重检验锁。

双重检验锁双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance == null ,一次是在同步块外,一次是在同步块内。

为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的 if,如果在同步块内不进行二次检验的话就会生成多个实例了。12345678910public static Singleton getSingleton () {if (instance == null ) { //Single Checkedsynchronized (Singleton.class) {if (instance == null ) { //Double Checkedinstance = new Singleton();}}}return instance ;}这段代码看起来很完美,很可惜,它是有问题。

主要在于 instance = new Singleton() 这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。给 instance 分配内存调用 Singleton 的构造函数来初始化成员变量将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)但是在 JVM 的即时编译器中存在指令重排序的优化。

也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。

我们只需要将 instance 变量声明成 volatile 就可以了。12345678910111213141516public class Singleton {private volatile static Singleton instance; //声明成 volatileprivate Singleton (){}public static Singleton getSingleton () {if (instance == null ) {synchronized (Singleton.class) {if (instance == null ) {instance = new Singleton();}}}return instance;}}有些人认为使用 volatile 的原因是可见性,也就是可以保证线程在本地不会存有 instance 的副本,每次都是去主内存中读取。

但其实是不对的。使用 volatile 的主要原因是其另一个特性:禁止指令重排序优化。

也就是说,在 volatile 变量的赋值操作后面会有一个内存屏障(生成的汇编代码上),读操作不会被重排序到内存屏障之前。比如上面的例子,取操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。

从「先行发生原则」的角度理解的话,就是对于一个 volatile 变量的写操作都先行发生于后面对这个变量的读操作(这里的“后面”是时间上的先后顺序)。但是特别注意在 Java 5 以前的版本使用了 volatile 的双检锁还是有问题的。

其原因是 Java 5 以前的 JMM (Java 内存模型)是存在缺陷的,即时将变量声明成 volatile 也不能完全避免重排序,主要是 volatile 变量前后的代码仍然存在重排序问题。这个 volatile 屏蔽重排序的问题在 Java 5 中才得以修复,所以在这之后才可以放心使用 volatile。

相信你不会喜欢这种复杂又隐含问题的方式,当然我们有更好的实现线程安全的单例模式的办法。饿汉式 static final field这种方法非常简单,因为单例的实例被声明成 static 和 final 变量了,在第一次加载类到内存中时就会初始化,所以创建实例本身是线程安全的。

12345678910public class Singleton {//类加载时就初始化private static final Singleton instance = new Singleton();private Singleton (){}public static Singleton getInstance (){return instance;}}这种写法如果完美的话,就没必要在啰嗦那么多双检锁的问题了。缺点是它不是一种懒加载模式(lazy initialization),单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。

饿汉式的创建方式在一些场景中将无法使用:譬如 Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。静态内部类 static nested class我比较倾向于使用静态内部类的方法,这种方法也是《Effective Java》上所推荐的。

123456789public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton (){}public 。

8. 如何写一个单例模式

class Single(object): _instance = None _is_init = False def __new__(cls, *args, **kw): if cls._instance is None: cls._instance = object.__new__(cls, *args, **kw) return cls._instance def __init__(self): if not Single._is_init: # 给对象进行来初始源化,添加相关2113属性 # 。

# 表示对象已经初始化完成了。 Single._is_init = True你学会了吗?学习更多编5261程的知识,不知道去哪里找资料4102,黑马程序员就有很多1653哦。

9. 单例模式怎样写

class StringManager {

private static StringManager instance;

private Map beanMap;

private StringManager() {

beanMap = new HashMap();

}

public static StringManager getInstance() {

if (instance == null) {

instance = new StringManager();

}

return instance;

}

public Object getBean(String beanName) {

return beanMap.get(beanName);

}

}

TAG标签:#单例 #