單例模式疾忍,是一種常用的軟件設計模式乔外。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統(tǒng)中一罩,應用該模式的類一個類只有一個實例杨幼。即一個類只有一個對象實例。
為什么要用單例模式
在實際的項目中,有一些東西是大家共用的差购,比如:系統(tǒng)配置四瘫、redis實例、數(shù)據(jù)庫實例等欲逃,我們不希望每個用戶在使用這些資源的時候找蜜,自己去新建一份實例,這樣會造成資源的浪費暖夭。
目的:保證一個類只有一個實例
使用場景:當你想控制實例個數(shù)锹杈,節(jié)省系統(tǒng)資源的時候
解決方案:判斷該類是否已經(jīng)有實例撵孤,如果有則返回迈着,沒有則創(chuàng)建
關鍵代碼:私有化構造函數(shù),讓使用方不能隨意的去實例
實現(xiàn)方案:懶漢邪码、餓漢裕菠、靜態(tài)內部類、枚舉
- 懶漢 - 線程不安全
package com.my.test.singleton;
//懶漢 - 線程不安全
public class SingletonExample01 {
private SingletonExample01(){
}
private static SingletonExample01 instance = null;
public static SingletonExample01 getInstance(){
if(instance == null){
instance = new SingletonExample01();
}
return instance;
}
}
- 懶漢 - 線程安全
package com.my.test.singleton;
//懶漢 - 線程安全
public class SingletonExample02 {
private SingletonExample02(){
}
private static SingletonExample02 instance = null;
public static synchronized SingletonExample02 getInstance(){
if(instance == null){
instance = new SingletonExample02();
}
return instance;
}
}
- 雙重校驗鎖
package com.my.test.singleton;
//懶漢 - 雙重校驗鎖
public class SingletonExample03 {
private SingletonExample03(){
}
private static volatile SingletonExample03 instance = null;
public static SingletonExample03 getInstance(){
if(instance == null){
synchronized (SingletonExample03.class){
if(instance == null){
instance = new SingletonExample03();
}
}
}
return instance;
}
}
- 餓漢模式
package com.my.test.singleton;
//餓漢模式
public class SingletonExample04 {
private SingletonExample04(){
}
// 方法一
// private static SingletonExample04 instance = new SingletonExample04();
// 方法二
private static SingletonExample04 instance = null;
static {
instance = new SingletonExample04();
}
public static SingletonExample04 getInstance(){
return instance;
}
}
- 靜態(tài)內部類
package com.my.test.singleton;
// 靜態(tài)內部類
public class SingletonExample05 {
private SingletonExample05(){
}
private static class InstanceSingletonExample05{
private static SingletonExample05 instance = new SingletonExample05();
}
public static SingletonExample05 getInstance(){
return InstanceSingletonExample05.instance;
}
}
- 枚舉
package com.my.test.singleton;
// 枚舉
public class SingletonExample06 {
private SingletonExample06(){
}
public static SingletonExample06 getInstance(){
return InstanceSingletonExample06.INSTANCE.getSingletonExample06();
}
private enum InstanceSingletonExample06{
INSTANCE;
private SingletonExample06 singletonExample06 = new SingletonExample06();
public SingletonExample06 getSingletonExample06(){
return singletonExample06;
}
}
}
- 枚舉2.0
package com.my.test.singleton;
public enum SingletonEnumExample{
INSTANCE;
public void test(){
// do everything
}
}
實例場景之 - 獲取jdbc連接
我們新增兩個類闭专,第一個是非單例的獲取jdbc連接
package com.mk.designDemo.singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MDataSourceNoSingle {
private static final Logger logger = LoggerFactory.getLogger(MDataSourceNoSingle.class);
private static Connection connection = null;
public Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://******:3306/*****?characterEncoding=UTF-8", "root", "root");
logger.info("線程{}實例化connection", Thread.currentThread().getName());
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
}
第二個使用了單例模式
package com.mk.designDemo.singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MDataSourceSingle {
private static final Logger logger = LoggerFactory.getLogger(MDataSourceSingle.class);
private static Connection connection = null;
static {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://******:3306/*****?characterEncoding=UTF-8", "root", "root");
logger.info("線程{}實例化connection", Thread.currentThread().getName());
} catch (ClassNotFoundException | SQLException e) {
logger.error(e.getMessage(), e);
}
}
private MDataSourceSingle() {
}
public static Connection getConnection() {
return connection;
}
}
然后我們寫了一個簡單的controller奴潘,里面有兩個接口,用來驗證結果
package com.mk.designDemo.controller;
import com.mk.designDemo.singleton.MDataSourceNoSingle;
import com.mk.designDemo.singleton.MDataSourceSingle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.Connection;
@RestController
public class SingletonController {
private static final Logger logger = LoggerFactory.getLogger(SingletonController.class);
private final static String sql = "select * from t_trade_date limit 10";
@RequestMapping(path = "/noSingleton")
public String noSingleton() {
MDataSourceNoSingle mDataSourceNoSingle = new MDataSourceNoSingle();
Connection connection = mDataSourceNoSingle.getConnection();
doExecute(connection, sql);
return "OK";
}
@RequestMapping(path = "/singleton")
public String singleton() {
doExecute(MDataSourceSingle.getConnection(), sql);
return "OK";
}
private void doExecute(Connection connection, String sql) {
logger.info("do execute sql:{}", sql);
}
}
當我們調用三次非單例的接口時影钉,查看日志輸出如下画髓,connection被實例化了多次:
2019-07-09 15:47:31.966 [http-nio-80-exec-1] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/noSingleton", parameters={}
2019-07-09 15:47:31.970 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.noSingleton()
2019-07-09 15:47:32.633 [http-nio-80-exec-1] INFO c.m.d.singleton.MDataSourceNoSingle - 線程http-nio-80-exec-1實例化connection
2019-07-09 15:47:32.633 [http-nio-80-exec-1] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:47:32.671 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:47:32.672 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:47:32.693 [http-nio-80-exec-1] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
2019-07-09 15:47:40.005 [http-nio-80-exec-4] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/noSingleton", parameters={}
2019-07-09 15:47:40.007 [http-nio-80-exec-4] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.noSingleton()
2019-07-09 15:47:40.361 [http-nio-80-exec-4] INFO c.m.d.singleton.MDataSourceNoSingle - 線程http-nio-80-exec-4實例化connection
2019-07-09 15:47:40.361 [http-nio-80-exec-4] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:47:40.362 [http-nio-80-exec-4] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:47:40.362 [http-nio-80-exec-4] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:47:40.363 [http-nio-80-exec-4] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
2019-07-09 15:47:48.459 [http-nio-80-exec-7] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/noSingleton", parameters={}
2019-07-09 15:47:48.461 [http-nio-80-exec-7] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.noSingleton()
2019-07-09 15:47:48.801 [http-nio-80-exec-7] INFO c.m.d.singleton.MDataSourceNoSingle - 線程http-nio-80-exec-7實例化connection
2019-07-09 15:47:48.801 [http-nio-80-exec-7] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:47:48.802 [http-nio-80-exec-7] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:47:48.802 [http-nio-80-exec-7] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:47:48.803 [http-nio-80-exec-7] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
然后我們調用單例的接口三次,日志輸出如下平委,我們可以看到,只有第一次進行了實例化廉赔,后面再也沒有繼續(xù)實例化
2019-07-09 15:49:22.868 [http-nio-80-exec-10] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/singleton", parameters={}
2019-07-09 15:49:22.871 [http-nio-80-exec-10] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.singleton()
2019-07-09 15:49:23.234 [http-nio-80-exec-10] INFO c.m.d.singleton.MDataSourceSingle - 線程http-nio-80-exec-10實例化connection
2019-07-09 15:49:23.235 [http-nio-80-exec-10] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:49:23.237 [http-nio-80-exec-10] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:49:23.237 [http-nio-80-exec-10] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:49:23.239 [http-nio-80-exec-10] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
2019-07-09 15:49:25.032 [http-nio-80-exec-1] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/singleton", parameters={}
2019-07-09 15:49:25.034 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.singleton()
2019-07-09 15:49:25.034 [http-nio-80-exec-1] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:49:25.035 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:49:25.036 [http-nio-80-exec-1] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:49:25.038 [http-nio-80-exec-1] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
2019-07-09 15:49:25.926 [http-nio-80-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - GET "/web/singleton", parameters={}
2019-07-09 15:49:25.926 [http-nio-80-exec-2] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped to public java.lang.String com.mk.designDemo.controller.SingletonController.singleton()
2019-07-09 15:49:25.927 [http-nio-80-exec-2] INFO c.m.d.controller.SingletonController - do execute sql:select * from t_trade_date limit 10
2019-07-09 15:49:25.928 [http-nio-80-exec-2] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2019-07-09 15:49:25.928 [http-nio-80-exec-2] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Writing ["OK"]
2019-07-09 15:49:25.929 [http-nio-80-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - Completed 200 OK
驗證通過碉纳,OVER铁孵!