单例模式(Singleton)是一种非常简单且容易理解的设计模式。顾名思义,单例即单一的实例,确切地讲就是指在某个系统中只存在一个实例,同时提供集中、统一的访问接口,以使系统行为保持协调一致
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:24
*/
public class Test01 {
private static final Test01 INSTANCE=new Test01();
private Test01(){
}
public static Test01 getINSTANCE() {
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test01.getINSTANCE().hashCode());
}).start();
}
}
}
私有的构造方法使得Test01完全被封闭起来 实例化工作是自己内部的事务
private static final 修饰 保证了 INSTANCE是私有的 ,不可见的不可访问的,static保证了静态性,在类被加载进内存时,就已经初始化 ,final保证INSTANCE是常量,是不能被修改的
外部只要调用公共的方法TEST01.getINSTANCE就可以获得唯一的实例对象了
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:24
*/
public class Test03 {
private static final Test03 INSTANCE;
static {
INSTANCE=new Test03();
}
private Test03(){
}
public static Test03 getINSTANCE() {
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test03.getINSTANCE().hashCode());
}).start();
}
}
}
此处将实例化操作放到静态代码块中
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:33
*/
public class Test02 {
private static Test02 test02;
private Test02(){};
public static Test02 getInstance(){
if (test02==null){
test02=new Test02();
}
return test02;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test02.getInstance().hashCode());
}).start();
}
}
}
恶汉模式如果没人使用,但是却实例化对象 ,这样一块内存区不是白浪费了 这样单杀了懒汉模式的写法
只有当某一个线程第一次调用getINSTANCE时才会进行实例化操作 之后再有线程访问直接返回对象
这样程序乍看确实没什么问题 但是在多线程环境下 可能会有多个线程进入到了getINSTANCE方法内,这样就会导致原来已经实例化的对象被覆盖掉
为了保证线程安全 我们给getINSTANCE方法加上 synchronized同步锁 下面看第四种写法
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:33
*/
public class Test04 {
private static Test04 test02;
private Test04(){};
public static synchronized Test04 getInstance(){
if (test02==null){
test02=new Test04();
}
return test02;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test04.getInstance().hashCode());
}).start();
}
}
}
这样确实没有什么问题 然而这样的做法是要付出一定代价的,试想,线程还没进入方法内部便不管三七二十一直接加锁排队,会造成线程阻塞,资源与时间被白白浪费。我们只是为了实例化一个单例对象而已,犯不上如此兴师动众,使用synchronized让所有请求排队等候。所以,要保证多线程并发下逻辑的正确性,同步锁一定要加得恰到好处
下面看第五种写法 在方法体内部加锁:
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:33
*/
public class Test05 {
private static Test05 test02;
private Test05(){};
public static Test05 getInstance(){
if (test02==null){
synchronized (Test05.class){
test02=new Test05();
}
}
return test02;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test05.getInstance().hashCode());
}).start();
}
}
}
这样在多线程环境也会有一定问题 ,可能会有多个线程同时通过了 tese02==null 的判断进入了方法里,这样也会造成重复的实例化
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:33
*/
public class Test06 {
private static volatile Test06 test02;
private Test06(){};
public static Test06 getInstance(){
if (test02==null){
synchronized (Test06.class){
if (test02==null){
test02=new Test06();
}
}
}
return test02;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test06.getInstance().hashCode());
}).start();
}
}
}
我们一共用了2个嵌套的判空逻辑,这就是懒加载模式的“双检锁”:外层放宽入口,保证线程并发的高效性;内层加锁同步,保证实例化的单次运行。如此里应外合,不仅达到了单例模式的效果,还完美地保证了构建过程的运行效率,一举两得。
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:51
*/
public class Test07 {
private Test07(){};
private static class Test0701{
private static final Test07 test07=new Test07();
}
public static Test07 getInstance(){
return Test0701.test07;
}
public static void main(String[] args) {
for (int i=0;i<1000;i++){
new Thread(()->{
System.out.println(Test07.getInstance().hashCode());
}).start();
}
}
}
package com.cyc.mystudy.singleton;
/**
* @Author cyc
* @create 2022/7/30 11:57
*/
public enum Test08 {
INSTANCE;
public void m(){
System.out.println("业务代码");
}
public static void main(String[] args) {
Test08.INSTANCE.m();
}
}
在一般情况下我们使用饿汉模式,恶汉模式不用担心多线程环境会出问题,写法上也比较简单,
我们不用为了省一点性能而去给自己造成麻烦