不起眼的文章

生几个我决定!

原本一个类需要生多少个,会受外界的影响(创建多少个实例),并且各个长得都不一样(实例对象的地址都不相同)

public class Singleton {

public Singleton() {
}
}


Singleton singleton1 = new Singleton();
Singleton singleton2 = new Singleton();

System.out.println(singleton1 == singleton2); //不同的实例对象地址


而现在我不一样了!现在这种环境下压力大,我自己决定生几个(就创建一个实例)。这种模式就是单列模式!


这就是单列模式?

public class Singleton {

private static Singleton singleton;

// 私有的构造方法,说明外界无法创建该类的实例对象
private Singleton() {
}
// 由自己创建实例,然后将创建的好的实例提供给外界访问
public static Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}

}


首先,就是禁止受外界影响(私有的构造方法)

其次,自己生,并且让外界知道自己的孩子(由自己创建实例对象,提供静态方法给外界访问)

提一嘴:虽然实例是唯一的,但是有可以有子类来继承。

但是,好像有个问题吧?

如果外界是一个一个的影响我(单线程),我可以控制得住,但如果出现了一大批人同时来影响我(多线程),我又该如何,或许我会乱成一团糟...(创建了不止一个实例)


解决多线程访问问题

那就是加锁!synchronized

装了一道门(加锁),外界只能一个一个的来访问我。

public class Singleton {

private static Singleton singleton;

// 私有的构造方法,说明外界无法创建该类的实例对象
private Singleton() {
}

// 在原有的代码上,加上锁,说明只有一个线程可以获取,下一个线程需要等待当前线程释放锁
public static synchronized Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}


但是,好像还是有个问题吧? 如果外界并不都是来影响我的,而是只是单纯访问我,那我岂不是降低了访问我的效率吗?(影响了性能)


那我就再优化(双重锁定)

我们并不将外界访问时都加锁(不锁住每个线程),而是将影响我的才加锁(当还未创建实例对象时,只有一个线程访问,然后创建了实例对象,接着其它线程访问的都是已经创建好的实例对象)。

public class Singleton {

private volatile static Singleton singleton;

// 私有的构造方法,说明外界无法创建该类的实例对象
private Singleton() {
}

// 不锁住所有线程,而是当类未创建实例时才加锁
public static synchronized Singleton getSingleton() {
if (singleton == null) { //第一道判断
synchronized (Singleton.class) {
if (singleton == null) { //第二道判断
singleton = new Singleton();
}
}
}
return singleton;
}
}


volatile 关键字:用于声明一个变量。它的作用是确保每次访问变量时都能读取到最新的值,而不是缓存的旧值。在多线程环境中,如果没有使用 volatile 关键字,变量的值可能会被多个线程缓存,导致线程之间的不一致性,从而引发错误。

你可能会问:为什么要进行两次 if (singleton == null) 的判断呢?

是这样的,你想想比如有两个线程 A-线程、B-线程:

两个线程同时经过了第一道 if (singleton == null) 判断。

接下来就是要经历锁,只会有一个线程获取锁,假设是 A-线程 获取了锁。

A-线程,创建了实例对象,..........,最终释放了锁。

B-线程 获取了锁,这时候如果没有进行第二道 if (singleton == null) 判断,就会造成再次创建实例对象。


不同生育方式(懒汉式、饿汉式)

上面讲的单列模式就是懒汉式,只有在线程通知我的时候我再去生育,也影响了性能。(被引用的时候,自己才会去实例化对象)

饿汉式,是我主动生育,不需要其他人来通知,只需要他们来访问。(使用静态初始化的方式,当类被加载的时候就已经实例化对象了)

public class Singleton {

private static Singleton singleton = new Singleton();

// 私有的构造方法,说明外界无法创建该类的实例对象
private Singleton() {
}

// 饿汉式,返回创建好的实例
public static synchronized Singleton getSingleton() {
return singleton;
}
}



0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
摆烂青年
下载 APP