最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析Spring IOC bean為什么默認(rèn)是單例

 更新時間:2023年12月14日 09:57:17   作者:Lzfnemo2009  
單例的意思就是說在 Spring IoC 容器中只會存在一個 bean 的實(shí)例,無論一次調(diào)用還是多次調(diào)用,始終指向的都是同一個 bean 對象,本文小編將和大家一起分析Spring IOC bean為什么默認(rèn)是單例,需要的朋友可以參考下

首先解釋一下什么是單例 bean?

單例的意思就是說在 Spring IoC 容器中只會存在一個 bean 的實(shí)例,無論一次調(diào)用還是多次調(diào)用,始終指向的都是同一個 bean 對象

用代碼來解釋單例 bean

public class UserService {
    public void sayHello() {
        System.out.println("hello");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
 
		<!-- scope 屬性就是用來設(shè)置 bean 的作用域的,不配置的話默認(rèn)就是單例,這里顯示配置了 singleton -->
    <bean id="userService" class="com.fyl.springboot.bean.singleton.UserService" scope="singleton"/>
 
</beans>
public class Demo {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans-singleton.xml");
 
        UserService service = context.getBean(UserService.class);
        UserService service1 = context.getBean(UserService.class);
        System.out.println(service == service1);
    }
}

運(yùn)行 main 方法最后會輸出:true,這就很明顯的說明了無論多少次調(diào)用 getBean 方法,最終得到的都是同一個實(shí)例。

把上面 xml 文件的配置修改一下,修改為:

<!-- scope 的值改為了 prototype,表示每次請求都會創(chuàng)建一個新的 bean -->
<bean id="userService" class="com.fyl.springboot.bean.singleton.UserService" scope="prototype"/>

然后再次運(yùn)行 main 方法,結(jié)果輸出:false,說明兩次調(diào)用 getBean 方法,得到的不是同一個實(shí)例。

了解了什么是單例 bean 之后,我們繼續(xù)來說說單例 bean 的線程安全問題

為什么會存在線程安全問題呢?

因?yàn)閷τ趩螌?shí)例來說,所有線程都共享同一個 bean 實(shí)例,自然就會發(fā)生資源的爭搶。

用代碼來說明線程不安全的現(xiàn)象

public class ThreadUnSafe {
 
    public int i;
 
    public void add() {
        i++;
    }
 
    public void sub() {
        i--;
    }
 
    public int getValue() {
        return i;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
 
    <bean id="threadUnSafe" class="com.fyl.springboot.bean.singleton.ThreadUnSafe" scope="singleton"/>
 
</beans>
public class Demo {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans-singleton.xml");
 
        for (int j = 0; j < 10; j++) {
            new Thread(() -> {
                ThreadUnSafe service = context.getBean(ThreadUnSafe.class);
                for (int i = 0; i < 1000; i++) {
                    service.add();
                }
                for (int i = 0; i < 1000; i++) {
                    service.sub();
                }
                System.out.println(service.getValue());
            }).start();
        }
    }
}

上面的代碼中,創(chuàng)建了 10 個線程來獲取 ThreadUnSafe 實(shí)例,并且循環(huán) 1000 次加法,循環(huán) 1000 次減法,并把最后的結(jié)果打印出來。理想的情況是每個線程打印出來的結(jié)果都是 0

先看一下運(yùn)行結(jié)果:

2073
1736
1080
1060
221
49
50
-231
-231
-231

從結(jié)果可以看出,運(yùn)行結(jié)果都不是 0,這明顯的是線程不安全??!

為什么會出現(xiàn)這種情況?

因?yàn)?10 個線程獲取的 ThreadUnSafe 實(shí)例都是同一個,并且 10 個線程都對同一個資源 i 發(fā)生了爭搶,所以才會導(dǎo)致線程安全問題的發(fā)生。

現(xiàn)在把 xml 文件中的配置做一下更改:scope 的值改為 prototype

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
 
    <!-- scope 的值改為 prototype -->
    <bean id="threadUnSafe" class="com.fyl.springboot.bean.singleton.ThreadUnSafe" scope="prototype"/>
 
</beans>

然后再次運(yùn)行 main 方法,發(fā)現(xiàn)無論運(yùn)行多少次,最后的結(jié)果都是 0,是線程安全的!

因?yàn)?prototype 作用域下,每次獲取的 ThreadUnSafe 實(shí)例都不是同一個,所以自然不會有線程安全的問題。

如果單例 bean 是一個無狀態(tài)的 bean,還會有線程安全問題嗎?

不會,無狀態(tài) bean 沒有實(shí)例對象,不能保存數(shù)據(jù),是不變類,是線程安全的。

public class ThreadSafe {
 
    public void getValue() {
        int val = 0;
        for (int i = 0; i < 1000; i++) {
            val++;
        }
        for (int i = 0; i < 1000; i++) {
            val--;
        }
        System.out.println(val);
    }
}
public class Demo {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans-singleton.xml");
 
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                ThreadSafe service = context.getBean(ThreadSafe.class);
                service.getValue();
            }).start();
        }
    }
}
 

運(yùn)行結(jié)果為 0

事實(shí)證明,無狀態(tài)的 bean 是線程安全的。(無狀態(tài) bean 應(yīng)該是這個意思,如有不對的地方,還望指出)

那么針對單例 bean,而且是有狀態(tài)的 bean,應(yīng)該如何保證線程安全呢?

那有人肯定會說了:既然是線程安全問題,那就加鎖唄!

毫無疑問加鎖確實(shí)可以,但是加鎖多多少少有點(diǎn)性能上的下降

加鎖代碼如下所示:

public class Demo {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans-singleton.xml");
 
        for (int j = 0; j < 10; j++) {
            new Thread(() -> {
                ThreadUnSafe service = context.getBean(ThreadUnSafe.class);
                synchronized (service) {
                    for (int i = 0; i < 1000; i++) {
                        service.add();
                    }
                    for (int i = 0; i < 1000; i++) {
                        service.sub();
                    }
                    System.out.println(service.getValue());
                }
            }).start();
        }
    }
}

還有一種方法是使用 ThreadLocal

ThreadLocal 簡單的說就是在自己線程內(nèi)創(chuàng)建一個變量的副本,那么線程操作的自然也就是自己線程內(nèi)的資源了,也就規(guī)避了線程安全問題。但是卻帶來了空間上的開銷。

使用方法如下:

public class ThreadUnSafe {
 
    ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
 
    public void add() {
        Integer i = threadLocal.get();
        if (i == null) {
            i = 0;
        }
        i++;
        threadLocal.set(i);
    }
 
    public void sub() {
        Integer i = threadLocal.get();
        i--;
        threadLocal.set(i);
    }
 
    public Integer getValue() {
        return threadLocal.get();
    }
}
public class Demo {
 
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:beans-singleton.xml");
 
        for (int j = 0; j < 10; j++) {
            new Thread(() -> {
                ThreadUnSafe service = context.getBean(ThreadUnSafe.class);
                for (int i = 0; i < 1000; i++) {
                    service.add();
                }
                for (int i = 0; i < 1000; i++) {
                    service.sub();
                }
                System.out.println(service.getValue());
            }).start();
        }
    }
}

使用 ThreadLocal 即使不加鎖也保證了輸出的結(jié)果都是 0

加鎖和使用 ThreadLocal 各有各的特點(diǎn)

  • 加鎖是以時間換空間
  • ThreadLocal 是以空間換時間

以上就是淺析Spring IOC bean為什么默認(rèn)是單例的詳細(xì)內(nèi)容,更多關(guān)于Spring IOC bean默認(rèn)單例的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程)

    Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程)

    這篇文章主要介紹了Maven在Windows中的配置以及IDE中的項目創(chuàng)建(圖文教程),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • SpringBoot 攔截器妙用你真的了解嗎

    SpringBoot 攔截器妙用你真的了解嗎

    關(guān)于springboot攔截器很多朋友掌握的不是多好,今天抽空給大家普及下這方面的知識,SpringBoot 攔截器妙用,讓你一個人開發(fā)整個系統(tǒng)的鑒權(quán)模塊,快來跟小編一起學(xué)習(xí)下吧
    2021-07-07
  • 詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問

    詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問

    本篇文章主要介紹了詳解關(guān)于springboot-actuator監(jiān)控的401無權(quán)限訪問,非常具有實(shí)用價值,有興趣的可以了解一下
    2017-09-09
  • Java實(shí)戰(zhàn)之用Spring開發(fā)條形碼和驗(yàn)證碼

    Java實(shí)戰(zhàn)之用Spring開發(fā)條形碼和驗(yàn)證碼

    這篇文章主要介紹了Java實(shí)戰(zhàn)之用Spring開發(fā)條形碼和驗(yàn)證碼,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • mybatis日志打印的兩款I(lǐng)DEA插件推薦

    mybatis日志打印的兩款I(lǐng)DEA插件推薦

    這篇文章主要給大家推薦介紹了關(guān)于mybatis日志打印的兩款I(lǐng)DEA插件,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-04-04
  • SpringBoot事件發(fā)布和監(jiān)聽詳解

    SpringBoot事件發(fā)布和監(jiān)聽詳解

    今天去官網(wǎng)查看spring boot資料時,在特性中看見了系統(tǒng)的事件及監(jiān)聽章節(jié),所以下面這篇文章主要給大家介紹了關(guān)于SpringBoot事件發(fā)布和監(jiān)聽的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-11-11
  • java類的定義與使用舉例詳解

    java類的定義與使用舉例詳解

    這篇文章主要給大家介紹了關(guān)于java類的定義與使用的相關(guān)資料,類的方法是用來定義類的行為,在方法中通過操作類的成員變量、編寫業(yè)務(wù)邏輯、返回 結(jié)果等實(shí)現(xiàn)類的業(yè)務(wù)行為,需要的朋友可以參考下
    2023-11-11
  • java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例

    java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例

    下面小編就為大家分享一篇java判斷用戶輸入的是否至少含有N位小數(shù)的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • 新版SpringSecurity安全配置說明

    新版SpringSecurity安全配置說明

    這篇文章主要介紹了新版SpringSecurity安全配置說明,在 Spring Security 5.7.0-M2 中,我們棄用了WebSecurityConfigurerAdapter,因?yàn)槲覀児膭钣脩艮D(zhuǎn)向基于組件的安全配置,需要的朋友可以參考下
    2023-07-07
  • 使用IntelliJ IDEA調(diào)式Stream流的方法步驟

    使用IntelliJ IDEA調(diào)式Stream流的方法步驟

    本文主要介紹了使用IntelliJ IDEA調(diào)式Stream流的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05

最新評論

禹州市| 陆丰市| 长垣县| 安泽县| 和硕县| 扎赉特旗| 沧源| 荃湾区| 辽宁省| 临泽县| 南川市| 大关县| 贵阳市| 汉寿县| 高雄市| 东山县| 邢台市| 梁山县| 望都县| 嵊州市| 青神县| 苗栗市| 鄂温| 道真| 从化市| 阜新| 陆川县| 南通市| 攀枝花市| 四川省| 平南县| 神木县| 五常市| 巨鹿县| 外汇| 易门县| 武夷山市| 永新县| 和平县| 邢台县| 延津县|