<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 22, comments - 32, trackbacks - 0, articles - 73
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    2024年10月31日

         摘要: ringboot3+springcloudstream4.x配置集成springcloudstream3.X 后逐漸淘汰了 @input @output @EnableBinding 這些注解 到4.X后這個(gè)注解都沒有了,全部轉(zhuǎn)向function 方式(關(guān)于function可以了解下)組件版本:springboot 3、 springcloud 2022.0.0、springc...  閱讀全文

    posted @ 2024-10-31 11:27 為自己代言 閱讀(18) | 評(píng)論 (0)編輯 收藏

    2024年10月27日

    1:nacos2.X 配置中心三個(gè)主要的參數(shù) dataId、group、namespace

       其中dataid 是指配置文件名稱;group:相當(dāng)于給配置文件分類;namespace:用來隔離環(huán)境的(例如:dev,test,product)

       比較關(guān)注的點(diǎn)是 bootstrap.yml; application.yml 這兩文件用途和加載順序

    1. bootstrap.yml 用于配置nacos地址,用戶名,密碼,命名空間(相當(dāng)要先連接上nacos),然后才能拉去nacos上的配置文件信息; 
    2. application.yml 文件用于配置在本地的配置文件(其實(shí)這個(gè)也可以放到nacos上)

      bootstrap配置文件是spring cloud新增的啟動(dòng)配置文件,需要引入spring-cloud-context依賴后,才會(huì)進(jìn)行加載(看spring cloud 2022版本以以前)。

      • bootstrap由父ApplicationContext加載,所以比application優(yōu)先加載

      • 因?yàn)閎ootstrap優(yōu)先于application加載,所以不會(huì)被覆蓋

      • 使用配置中心spring cloud config時(shí),需要在bootstarp中配置配置中心的地址,從而實(shí)現(xiàn)父ApplicationContext加載時(shí),從配置中心拉去相應(yīng)的配置到應(yīng)用中。

      它們加載順序:bootstrap.yaml文件生效后,去nacos拉去完配置信息后,與本地的application.yaml配置信息進(jìn)行合并,然后加載到spring容器中

      在springboot工程中使用基礎(chǔ)上使用兩個(gè)注釋:@RefreshScope 放在類上和@value 配置使用 
      要實(shí)現(xiàn)取值和動(dòng)態(tài)刷新通過實(shí)驗(yàn)證明使用@NacosValue是不行了,因?yàn)槭褂昧薙pring Cloud的依賴包,所以根據(jù)官方文檔顯示,要通過 Spring Cloud 原生注解 @RefreshScope + @Value 來實(shí)現(xiàn)配置自動(dòng)更新,我們可以用下面的方法達(dá)到同樣的效。
      nacos client 從服務(wù)端拉取配置信息會(huì)放到client 本地緩存起來 默認(rèn)目錄:${user}\nacos\config 下(拉到調(diào)試時(shí)候有用)
                              
      詳細(xì)文章 :https://developer.aliyun.com/article/859891

        

    posted @ 2024-10-27 22:16 為自己代言 閱讀(33) | 評(píng)論 (0)編輯 收藏

    2021年9月26日

         摘要: 1:軟件分層圖:2:詳細(xì)分層架構(gòu)圖:3:適用業(yè)務(wù)快速發(fā)展的分層圖COLA 是 Clean Object-Oriented and Layered Architecture的縮寫,代表“整潔面向?qū)ο蠓謱蛹軜?gòu)”。 目前COLA已經(jīng)發(fā)展到COLA 4.0。COLA分為兩個(gè)部分,COLA架構(gòu)和COLA組件。https://github.com/alibaba/COLA?spm=at...  閱讀全文

    posted @ 2021-09-26 18:09 為自己代言| 編輯 收藏

    2021年7月12日

    InnoDB的鎖

    InnoDB的行鎖:共享鎖、排他鎖、MDL鎖

    共享鎖:又稱讀鎖、S鎖。一個(gè)事務(wù)獲取一個(gè)數(shù)據(jù)行的共享鎖,其他事務(wù)能獲取該行對(duì)應(yīng)的共享鎖,但不能獲得排他鎖;即一個(gè)事務(wù)在讀取一個(gè)數(shù)據(jù)行時(shí),其他事務(wù)也可以讀,但不能對(duì)數(shù)據(jù)進(jìn)行增刪改查。

    應(yīng)用:

    1.自動(dòng)提交模式下的select查詢,不加任何鎖,直接返回查詢結(jié)果

    2.通過select……lock in share mode在被讀取的行記錄或范圍上加一個(gè)讀鎖,其他事務(wù)可以讀,但是申請(qǐng)加寫鎖會(huì)被阻塞

    排他鎖:又稱寫鎖、X鎖。一個(gè)事務(wù)獲取了一個(gè)數(shù)據(jù)行的寫鎖,其他事務(wù)就不能再獲取該行的其他鎖,寫鎖優(yōu)先級(jí)最高。

    應(yīng)用:

    1.一些DML操作會(huì)對(duì)行記錄加寫鎖

    2.select for update會(huì)對(duì)讀取的行記錄上加一個(gè)寫鎖,其他任何事務(wù)都不能對(duì)鎖定的行加任何鎖,否則會(huì)被阻塞

    MDL鎖:MySQL5.5引入,用于保證表中元數(shù)據(jù)的信息。在會(huì)話A中,表開啟了查詢事務(wù)后,會(huì)自動(dòng)獲得一個(gè)MDL鎖,會(huì)話B就不能執(zhí)行任何DDL語句的操作

    行鎖實(shí)現(xiàn)方式

    InnoDB 行鎖是通過給索引上的索引項(xiàng)加鎖來實(shí)現(xiàn)的,這一點(diǎn) MySQL 與 Oracle 不同,后者是 通過在數(shù)據(jù)塊中對(duì)相應(yīng)數(shù)據(jù)行加鎖來實(shí)現(xiàn)的。InnoDB 這種行鎖實(shí)現(xiàn)特點(diǎn)意味著:只有通過 索引條件檢索數(shù)據(jù),InnoDB 才使用行級(jí)鎖,否則,InnoDB 將使用表鎖! 在實(shí)際應(yīng)用中,要特別注意 InnoDB 行鎖的這一特性,不然的話,可能導(dǎo)致大量的鎖沖突, 從而影響并發(fā)性能。

    行鎖的三種算法

    InnoDB 存儲(chǔ)引擎有三種行鎖的算法,其分別是:

    • Record Lock: 單個(gè)行記錄上的鎖
    • Gap Lock: 間隙鎖,鎖定一個(gè)范圍,但不包含記錄本身
    • Next-Key 鎖: Gap Lock + Record Lock,鎖定一個(gè)范圍,并且會(huì)鎖定記錄本身

    RC模式下只采用Record Lock,RR模式下采用了Next-Key

    加鎖場(chǎng)景分析

    • 主鍵索引

    如果我們加鎖的行上存在主鍵索引,那么就會(huì)在這個(gè)主鍵索引上添加一個(gè) Record Lock。

    • 輔助索引

    如果我們加鎖的行上存在輔助索引,那么我們就會(huì)在這行的輔助索引上添加 Next-Key Lock,并在這行之后的輔助索引上添加一個(gè) Gap Lock

    輔助索引上的 Next-Key Lock 和 Gap Lock 都是針對(duì) Repeatable Read 隔離模式存在的,這兩種鎖都是為了防止幻讀現(xiàn)象的發(fā)生。

    • 唯一的輔助索引

    這里有一個(gè)特殊情況,如果輔助索引是唯一索引的話,MySQL 會(huì)將 Next-Key Lock 降級(jí)為 Record Lock,只會(huì)鎖定當(dāng)前記錄的輔助索引。

    如果唯一索引由多個(gè)列組成的,而我們只鎖定其中一個(gè)列的話,那么此時(shí)并不會(huì)進(jìn)行鎖降級(jí),還會(huì)添加 Next-Key Lock 和 Gap Lock。

    • Insert 語句

    在 InnoDB 存儲(chǔ)引擎中,對(duì)于 Insert 的操作,其會(huì)檢查插入記錄的下一條記錄是否被鎖定,若已經(jīng)被鎖定,則不允許查詢。

    意向鎖

    意向鎖可以分為意向共享鎖(Intention Shared Lock, IS)和意向排他鎖(Intention eXclusive Lock, IX)。但它的鎖定方式和共享鎖和排他鎖并不相同,意向鎖上鎖只是表示一種“意向”,并不會(huì)真的將對(duì)象鎖住,讓其他事物無法修改或訪問。例如事物T1想要修改表test中的行r1,它會(huì)上兩個(gè)鎖:

    1. 在表test上意向排他鎖
    2. 在行r1上排他鎖

    事物T1在test表上上了意向排他鎖,并不代表其他事物無法訪問test了,它上的鎖只是表明一種意向,它將會(huì)在db中的test表中的某幾行記錄上上一個(gè)排他鎖。


    意向共享鎖 意向排他鎖 共享鎖 排他鎖
    意向共享鎖 兼容 兼容 兼容 不兼容
    意向排他鎖 兼容 兼容 不兼容 不兼容
    共享鎖 兼容 不兼容 兼容 不兼容
    排他鎖 不兼容 不兼容 不兼容 不兼容

    一致性非鎖定讀

    一致性非鎖定讀是指 InnoDB 存儲(chǔ)引擎通過行多版本控制(multi version)的方式來讀取當(dāng)前執(zhí)行時(shí)間數(shù)據(jù)庫中行的數(shù)據(jù)。具體來說就是如果一個(gè)事務(wù)讀取的行正在被鎖定,那么它就會(huì)去讀取這行數(shù)據(jù)之前的快照數(shù)據(jù),而不會(huì)等待這行數(shù)據(jù)上的鎖釋放。這個(gè)讀取流程如圖1所示:

    圖1

    行的快照數(shù)據(jù)是通過undo段來實(shí)現(xiàn)的,而undo段用來回滾事務(wù),所以快照數(shù)據(jù)本身沒有額外的開銷。此外,讀取快照數(shù)據(jù)時(shí)不需要上鎖的,因?yàn)闆]有事務(wù)會(huì)對(duì)快照數(shù)據(jù)進(jìn)行更改。

    MySQL 中并不是每種隔離級(jí)別都采用非一致性非鎖定讀的讀取模式,而且就算是采用了一致性非鎖定讀,不同隔離級(jí)別的表現(xiàn)也不相同。在 READ COMMITTED 和 REPEATABLE READ 這兩種隔離級(jí)別下,InnoDB存儲(chǔ)引擎都使用一致性非鎖定讀。但是對(duì)于快照數(shù)據(jù),READ COMMITTED 隔離模式中的事務(wù)讀取的是當(dāng)前行最新的快照數(shù)據(jù),而 REPEATABLE READ 隔離模式中的事務(wù)讀取的是事務(wù)開始時(shí)的行數(shù)據(jù)版本。

    一致性鎖定讀

    在 InnoDB 存儲(chǔ)引擎中,select語句默認(rèn)采取的是一致性非鎖定讀的情況,但是有時(shí)候我們也有需求需要對(duì)某一行記錄進(jìn)行鎖定再來讀取,這就是一致性鎖定讀。

    InnoDB 對(duì)于select語句支持以下兩種鎖定讀:

    • select ... for update
    • select ... lock in share mode

    select ... for update會(huì)對(duì)讀取的記錄加一個(gè)X鎖,其他事務(wù)不能夠再來為這些記錄加鎖。select ... lock in share mode會(huì)對(duì)讀取的記錄加一個(gè)S鎖,其它事務(wù)能夠再為這些記錄加一個(gè)S鎖,但不能加X鎖。

    對(duì)于一致性非鎖定讀,即使行記錄上加了X鎖,它也是能夠讀取的,因?yàn)樗x取的是行記錄的快照數(shù)據(jù),并沒有讀取行記錄本身。

    select ... for updateselect ... lock in share mode這兩個(gè)語句必須在一個(gè)事務(wù)中,當(dāng)事務(wù)提交了,鎖也就釋放了。因此在使用這兩條語句之前必須先執(zhí)行begin, start transaction,或者執(zhí)行set autocommit = 0

    InnoDB 在不同隔離級(jí)別下的一致性讀及鎖的差異

    consisten read //一致性讀
    share locks //共享鎖
    Exclusive locks //排他鎖
    


    讀未提交 讀已提交 可重復(fù)讀 串行化
    SQL 條件



    select 相等 None locks Consisten read/None lock Consisten read/None lock Share locks

    范圍 None locks Consisten read/None lock Consisten read/None lock Share Next-Key
    update 相等 Exclusive locks Exclusive locks Exclusive locks Exclusive locks

    范圍 Exclusive next-key Exclusive next-key Exclusive next-key Exclusive next-key
    Insert N/A Exclusive locks Exclusive locks Exclusive locks Exclusive locks
    Replace 無鍵沖突 Exclusive locks Exclusive locks Exclusive locks Exclusive locks

    鍵沖突 Exclusive next-key Exclusive next-key Exclusive next-key Exclusive next-key
    delete 相等 Exclusive locks Exclusive locks Exclusive locks Exclusive locks

    范圍 Exclusive next-key Exclusive next-key Exclusive next-key Exclusive next-key
    Select … from … Lock in share mode 相等 Share locks Share locks Share locks Share locks

    范圍 Share locks Share locks Exclusive next-key Exclusive next-key
    Select * from … For update 相等 Exclusive locks Exclusive locks Exclusive locks Exclusive locks

    范圍 Exclusive locks Exclusive locks Exclusive next-key Exclusive next-key
    Insert into … Select … innodb_locks_ unsafe_for_bi nlog=off Share Next-Key Share Next-Key Share Next-Key Share Next-Key
    (指源表鎖) innodb_locks_ unsafe_for_bi nlog=on None locks Consisten read/None lock Consisten read/None lock Share Next-Key
    create table … Select … innodb_locks_ unsafe_for_bi nlog=off Share Next-Key Share Next-Key Share Next-Key Share Next-Key
    (指源表鎖) innodb_locks_ unsafe_for_bi nlog=on None locks Consisten read/None lock Consisten read/None lock Share Next-Key
    在了解 InnoDB 鎖特性后,用戶可以通過設(shè)計(jì)和 SQL 調(diào)整等措施減少鎖沖突和死鎖,包括:
    • 盡量使用較低的隔離級(jí)別;
    • 精心設(shè)計(jì)索引,并盡量使用索引訪問數(shù)據(jù),使加鎖更精確,從而減少鎖沖突的機(jī)會(huì);
    • 選擇合理的事務(wù)大小, 小事務(wù)發(fā)生鎖沖突的幾率也更小;
    • 給記錄集顯示加鎖時(shí),最好一次性請(qǐng)求足夠級(jí)別的鎖。比如要修改數(shù)據(jù)的話,最好直接申請(qǐng)排他鎖,而不是先申請(qǐng)共享鎖,修改時(shí)再請(qǐng)求排他鎖,這樣容易產(chǎn)生死鎖;
    • 不同的程序訪問一組表時(shí),應(yīng)盡量約定以相同的順序訪問各表,對(duì)一個(gè)表而言,盡可能以固定的順序存取表中的行。這樣可以大大減少死鎖的機(jī)會(huì);
    • 盡量用相等條件訪問數(shù)據(jù),這樣可以避免間隙鎖對(duì)并發(fā)插入的影響;
    • 不要申請(qǐng)超過實(shí)際需要的鎖級(jí)別;除非必須,查詢時(shí)不要顯示加鎖;
    • 對(duì)于一些特定的事務(wù),可以使用表鎖來提高處理速度或減少死鎖的可能。

    參考資料

    1.https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-intention-locks  mysql官網(wǎng)開發(fā)手冊(cè)

    2.《MySQL 技術(shù)內(nèi)幕 – InnoDB 存儲(chǔ)引擎》

    3.《深入淺出MySQL》

    4.https://www.modb.pro/db/33873


    posted @ 2021-07-12 15:38 為自己代言 閱讀(115) | 評(píng)論 (0)編輯 收藏

    2021年6月4日

    整體架構(gòu)

    從日志生成到抓取、存儲(chǔ)、分析、展現(xiàn)的多個(gè)系統(tǒng)間交互過程。


    image

    EagleEye 的核心

    • TraceId
    在復(fù)雜的分布式系統(tǒng)環(huán)境下,EagleEye是一個(gè)有廣泛用途的調(diào)用分析和問題排查工具。與一般的調(diào)用信息埋點(diǎn)日志相比,EagleEye埋點(diǎn)的一個(gè)顯著的不同點(diǎn)在于它的每條日志都有與每次請(qǐng)求關(guān)聯(lián)的上下文ID,我們稱為TraceId。通過TraceId,后期的日志處理時(shí)可以把一次前端請(qǐng)求在不同服務(wù)器記錄的調(diào)用日志關(guān)聯(lián)起來,重新組合成當(dāng)時(shí)這個(gè)請(qǐng)求的調(diào)用鏈。因此,EagleEye不僅可以分析到應(yīng)用之間的直接調(diào)用關(guān)系,還可以得到他們的間接調(diào)用關(guān)系、以及上下游的業(yè)務(wù)處理信息;對(duì)于調(diào)用鏈的底層系統(tǒng),可以追溯到它的最上層請(qǐng)求來源以及中間經(jīng)過的所有節(jié)點(diǎn);對(duì)于調(diào)用鏈的上層入口,可以收集到它的整棵調(diào)用樹,從而定位下游系統(tǒng)的處理瓶頸,當(dāng)下游某個(gè)應(yīng)用有異常發(fā)生時(shí),能迅速定位到問題發(fā)生的位置。

    image

    如上圖所示,應(yīng)用A是接受到來自用戶瀏覽器的Web請(qǐng)求的前端服務(wù)器,它是一條調(diào)用鏈的開始端,在TBSession和EagleEyeFilter中都做了EagleEye上下文埋點(diǎn)。請(qǐng)求收到后它會(huì)先調(diào)用EagleEye StartTrace生成TraceId并放置在當(dāng)前線程的ThreadLocal,日志埋點(diǎn)請(qǐng)求信息(如URL、SessionId、UserId等)。在請(qǐng)求處理完畢提交相應(yīng)時(shí),再調(diào)用EndTrace清理線程中的EagleEye信息。 在應(yīng)用A調(diào)用應(yīng)用B、C的HSF服務(wù),或者發(fā)送Notify消息時(shí),TraceId被包含在EagleEye上下文中,隨網(wǎng)絡(luò)請(qǐng)求到達(dá)應(yīng)用B、C、D、E之中,并放置在線程ThreadLocal內(nèi),因此后續(xù)調(diào)用到的這些系統(tǒng)都會(huì)有EagleEye這次請(qǐng)求的上下文。這些系統(tǒng)再發(fā)起網(wǎng)絡(luò)請(qǐng)求時(shí),也類似的攜帶了上下文信息的。

    • RpcId

    為了區(qū)別同一個(gè)調(diào)用鏈下多個(gè)網(wǎng)絡(luò)調(diào)用的順序和嵌套層次,EagleEye還需要傳輸和記錄RpcId。 RpcId用0.X1.X2.X3.....Xi來表示,Xi都是非負(fù)整數(shù),根節(jié)點(diǎn)的RpcId固定從0開始,第一層網(wǎng)絡(luò)調(diào)用的RpcId是0.X1,第二層的則為0.X1.X2,依次類推。*例如,從根節(jié)點(diǎn)發(fā)出的調(diào)用的RpcId是0.1、0.2、0.3,RpcId是0.1的節(jié)點(diǎn)發(fā)出的RpcId則為0.1.1、0.1.2、0.1.3。如下圖所示

    image


    通過RpcId,可以準(zhǔn)確的還原出調(diào)用鏈上每次調(diào)用的層次關(guān)系和兄弟調(diào)用之間的先后順序。 例如上圖應(yīng)用 G 的兩次調(diào)用0.2.1.1和0.1.2.1,可以看出對(duì) DB 的訪問0.2.1.1源于 C 到 G 的調(diào)用0.2.1,對(duì) Tair 的訪問0.1.2.1源于B 到 G 的調(diào)用0.1.2。 很多調(diào)用場(chǎng)景會(huì)比上面說的完全同步的調(diào)用更為復(fù)雜,比如會(huì)遇到異步、單向、廣播、并發(fā)、批處理等等,這時(shí)候需要妥善處理好ThreadLocal上的調(diào)用上下文,避免調(diào)用上下文混亂和無法正確釋放。另外,采用多級(jí)序號(hào)的RpcId設(shè)計(jì)方案會(huì)比單級(jí)序號(hào)遞增更容易準(zhǔn)確還原當(dāng)時(shí)的調(diào)用情況。



    posted @ 2021-06-04 15:36 為自己代言 閱讀(578) | 評(píng)論 (0)編輯 收藏

    2021年3月24日

    1:分布鎖有好多實(shí)現(xiàn)方式
    •  基于數(shù)據(jù)庫實(shí)現(xiàn)
          這個(gè)實(shí)現(xiàn)方式比較復(fù)雜,考慮因素比較多,比如:超時(shí),非公平鎖,非重入等會(huì)有各種各樣的問題,在解決問題的過程中會(huì)使整個(gè)方案變得越來越復(fù)雜。操作數(shù)據(jù)庫需要一定的開銷,性能問題需要考慮      
    • 基于redis實(shí)現(xiàn)(這個(gè)對(duì)于不太敏感的場(chǎng)景可以使用,由于redis集群和單機(jī),還有客戶端,版本等多方面因素考慮情況比較多)
           性能好。使用緩存實(shí)現(xiàn)分布式鎖的缺點(diǎn) 其數(shù)據(jù)庫一樣
    • 基于zookeeper實(shí)現(xiàn)(這個(gè)是最終也是最好最可靠的)
           創(chuàng)建臨時(shí)節(jié)點(diǎn),可以解決單機(jī),鎖無法釋放,非阻塞,不可沖入,非公平的問題
     
        總結(jié)
    從理解的難易程度角度(從低到高)

    數(shù)據(jù)庫 > 緩存 > Zookeeper

    從實(shí)現(xiàn)的復(fù)雜性角度(從低到高)

    Zookeeper > 緩存 > 數(shù)據(jù)庫

    從性能角度(從高到低)

    緩存 > Zookeeper >= 數(shù)據(jù)庫

    從可靠性角度(從高到低)

    Zookeeper > 緩存 > 數(shù)據(jù)庫
    下面講基于redis實(shí)現(xiàn)分布鎖代碼:RedisTemplate 客戶端 lettuce


    @Service
    public class RedisDistributedLockUtils {

        @Autowired
        
    private RedisTemplate redisTemplate;

        
    private static final Long RELEASE_SUCCESS = 1L;

        
    private static final long DEFAULT_TIMEOUT = 1000 * 10;
        
    //因?yàn)橐褂胠ua 腳本是因?yàn)?nbsp;redis 執(zhí)行l(wèi)ua腳本是原子操作
        private static final String UNLOCK_LUA= "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

        
    /**
         * 實(shí)時(shí)獲取鎖
         *
         * 嘗試獲取分布式鎖 將redis版本升級(jí)到2.1以上(spring-boot-starter-data-redis 版本 2.X以上),然后使用setIfAbsent 不存在
         * 當(dāng)setIfAbsent成功之后斷開連接,下面設(shè)置過期時(shí)間的代碼 stringRedisTemplate.expire(key,timeout);是無法執(zhí)行的,這時(shí)候就會(huì)有大量沒有過期時(shí)間的數(shù)據(jù)存在數(shù)據(jù)庫
         * 
    @param lockKey    鎖
         * 
    @param requestId  請(qǐng)求標(biāo)識(shí)
         * 
    @param expireTime 超期時(shí)間
         * 
    @return 是否獲取成功
         
    */
        
    public boolean trySetDistributedLock(String lockKey, String requestId, long expireTime) {
            
    return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId,0 == expireTime ? DEFAULT_TIMEOUT : expireTime, TimeUnit.MILLISECONDS);
        }

        
    /**
         * 以阻塞方式的獲取鎖
         * 
    @param key
         * 
    @param value
         * 
    @param timeout
         * 
    @return
         
    */
        
    public boolean setDistributedLock(String key, String value, long timeout) {
            Boolean lock 
    = false;
            
    long start = System.currentTimeMillis();
            
    while (!lock && (System.currentTimeMillis() - start < timeout)) {
                
    //執(zhí)行set命令
                lock = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS);
                
    //不頻繁去獲取鎖
                try {
                    
    if (!lock) {
                        Thread.sleep(
    60);
                    }
                } 
    catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
    return lock;
        }

        
    public boolean releaseLock(String key, String value) {
            
    // 使用Lua腳本:先判斷是否是自己設(shè)置的鎖,再執(zhí)行刪除
            
    // 使用lua腳本刪除redis中匹配value的key,可以避免由于方法執(zhí)行時(shí)間過長而redis鎖自動(dòng)過期失效的時(shí)候誤刪其他線程的鎖
            
    // spring自帶的執(zhí)行腳本方法中,集群模式直接拋出不支持執(zhí)行腳本的異常EvalSha is not supported in cluster environment
            
    // 所以只能拿到原redis的connection來執(zhí)行腳本

            List
    <String> keys = new ArrayList<>();
            keys.add(key);
            List
    <String> args = new ArrayList<>();
            args.add(value);
            Long result 
    = (Long)redisTemplate.execute(new RedisCallback<Long>() {
                @Override
                
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
                    Object nativeConnection 
    = connection.getNativeConnection();
                    
    // 集群模式和單機(jī)模式雖然執(zhí)行腳本的方法一樣,但是沒有共同的接口,所以只能分開執(zhí)行
                    
    // 集群模式
                    if (nativeConnection instanceof JedisCluster) {
                        
    return (Long)((JedisCluster)nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
                    
    //客戶端是Jedis時(shí)候(單機(jī)模式)
                    else if (nativeConnection instanceof Jedis) {
                        
    return (Long)((Jedis)nativeConnection).eval(UNLOCK_LUA, keys, args);
                    }
                    
    //這里使用 redisTemplate 中l(wèi)ettuce 客戶端
                    else{
                        DefaultRedisScript
    <Long> redisScript = new DefaultRedisScript<>();
                        redisScript.setScriptText(UNLOCK_LUA);
                        redisScript.setResultType(Long.
    class);
                        
    return (Long)redisTemplate.execute(redisScript, keys, value);
                    }
                }
            });
            
    //返回最終結(jié)果
            return RELEASE_SUCCESS.equals(result);
        }
    }
    基于zookeeper實(shí)現(xiàn)下期補(bǔ)上:


    介紹分布式鎖文章寫的比較詳細(xì):
    https://blog.csdn.net/u010963948/article/details/79006572

    posted @ 2021-03-24 20:11 為自己代言 閱讀(206) | 評(píng)論 (0)編輯 收藏

    2020年7月24日

    函數(shù)式接口的特征

    1、三種方法

    • 唯一的抽象方法
    • 使用default定義普通方法(默認(rèn)方法),通過對(duì)象調(diào)用。
    • 使用static定義靜態(tài)方法,通過接口名調(diào)用。

    2、一個(gè)新注解@FunctionInterface

    • 注解@FunctionalInterface告訴編譯器這是一個(gè)函數(shù)式接口,明確這個(gè)函數(shù)中只有一個(gè)抽象方法,當(dāng)你嘗試在接口中編寫多個(gè)抽象方法的時(shí)候編譯器將不允許,但是可以有多個(gè)非抽象方法。

    • 不過Object類的方法可以定義為抽象方法,因?yàn)榻涌诘膶?shí)現(xiàn)類一定是Object的子類

    • 如果接口被標(biāo)注了@FunctionalInterface,這個(gè)類就必須符合函數(shù)式接口的規(guī)范

    • 即使一個(gè)接口沒有標(biāo)注@FunctionalInterface,如果這個(gè)接口滿足函數(shù)式接口規(guī)則,依舊被當(dāng)作函數(shù)式接口。

    3JDK 1.8 新增加的函數(shù)接口包
       

        java.util.function.*
        java.util.function 它包含了很多接口,用來支持 Java的 函數(shù)式編程,它們大致分為五類:

        
       

     4、代碼樣例

        
        /**
         *JDK 8 函數(shù)式接口  Supplier、Function、Consumer、Predicate
         *
         * @param args
         * @throws Exception
         
    */

        public static void main(String[] args) throws Exception {
            ThreadPoolExecutor executor = (ThreadPoolExecutor)newFixedThreadPool(10);
            //1:JDK8以前,通過匿名內(nèi)部類實(shí)現(xiàn)函數(shù)式接口
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("JDK8以前,通過匿名內(nèi)部類實(shí)現(xiàn)函數(shù)式接口");
                }
            });
            //2:JDK8以后可以使用lambda 表達(dá)式來實(shí)現(xiàn),lambda表達(dá)式就是為了優(yōu)化匿名內(nèi)部類而生(分開寫效果)
            Thread thread = new Thread(() -> System.out.println("task running !"));
            Runnable r = () -> System.out.println("JDK8以后可以使用lambda 表達(dá)式來實(shí)現(xiàn),lambda表達(dá)式就是為了優(yōu)化匿名內(nèi)部類而生(分開寫效果)!");
            executor.submit(r);
            //3:合并起來效果
            executor.submit(() -> {
                System.out.println("JDK8以后可以使用lambda 表達(dá)式來實(shí)現(xiàn),lambda表達(dá)式就是為了優(yōu)化匿名內(nèi)部類而生!");
            });

            //4:其它 Supplier、Function、Consumer、Predicate 都可以用lambda 表達(dá)式來實(shí)現(xiàn)
            Supplier<String> supplier = () -> "我是SuSupplier";
            Supplier<Integer> supplier2 = () -> new Integer(1);
            System.out.println("supplier=" + supplier.get() + ";supplier2=" + supplier2.get());

            //5: Function功能型函數(shù)式接口 Function<T, R> 接受一個(gè)輸入?yún)?shù)T,返回一個(gè)結(jié)果R
            Function<String,Integer> function=str -> Integer.parseInt(str);
            Function<Integer,String> fun2 = item -> item+"";
            System.out.println("輸入字符型 1 返回int型結(jié)果:"+function.apply("1"));
            System.out.println("輸入整型 1 返回字符型結(jié)果:"+fun2.apply(2));

            //6: Consumer 一個(gè)接受單個(gè)輸入?yún)?shù)并且不返回結(jié)果的操作。 與大多數(shù)其他函數(shù)接口不同, Consumer接口期望通過接受參數(shù),改普通對(duì)象引用值(說明白點(diǎn)就是對(duì)原來的值進(jìn)行加工,注意返回值 void)
            Consumer<StringBuffer> consumer= sb->sb.append("-yyy");
            StringBuffer sb1=new StringBuffer().append("111");
            consumer.accept(sb1);
            //改變sb的內(nèi)部引用值
            System.out.println("=========s="+sb1.toString());

            //7: Predicate<T> 斷言型接口常用于集合的過濾,得到一個(gè)新的集合 Stream filter(Predicate<? super T> predicate);
            Predicate<Integer> predicate = age -> age > 18;
            Predicate<String> predicate2 = str -> str != null;
            System.out.println(predicate.test(19));
            System.out.println(predicate2.test(null));
            //我們常用集合過濾類就是對(duì)這個(gè)接口實(shí)現(xiàn)類 其中 filter(Predicate<? super T> predicate) 用的就是這個(gè)接口
            List<String> list= Lists.newArrayList("1","2","2","3","4","4","8");
            list.stream().map(s -> Long.parseLong(s)).distinct().filter(s -> s < 10).collect(Collectors.toList()).forEach(-> System.out.println(u));

            //總結(jié),以上的例子其實(shí)都是JDK8 lambda 表達(dá)式簡潔的寫法,而且全是合并寫的,并沒有分開步驟寫(所有函數(shù)性接口,都可以用lambda 表達(dá)式簡潔寫法)

            
    //關(guān)閉線程池
            executor.shutdownNow();
        }

    posted @ 2020-07-24 15:46 為自己代言 閱讀(1329) | 評(píng)論 (0)編輯 收藏

    2020年7月23日


    JDK 8 中 CompletableFuture 是對(duì) Future 的增強(qiáng) 大大簡化了異步編程步驟,在Spring 框架中配合@EnableAsync @Async 更加事辦功倍。

    1:在JDK 8 之前實(shí)現(xiàn)多線必需實(shí)現(xiàn)兩個(gè)接口 Runnable 不帶返回值,另一個(gè)Callable帶返回值的接口,配合ThreadPoolTaskExecutor.submit(Callable callable) 返回一個(gè)Future對(duì)象。 使用Future獲得異步執(zhí)行結(jié)果時(shí),要么調(diào)用阻塞方法get(),要么輪詢看isDone()是否為true,這兩種方法都不是很好,因?yàn)橹骶€程也會(huì)被迫等待,而CompletableFuture出現(xiàn)改變了這個(gè)問題,而且提供更多并且強(qiáng)大的其它功能。
    2:CompletableFuture簡介 CompletableFuture<T> implements Future<T>, CompletionStage<T> 其實(shí)CompletableFuture 除了實(shí)現(xiàn)原來的Future 接口外,其它大部分方法都是在CompletionStage中 CompletableFuture 類圖
    大致介紹下completableFuture的命名規(guī)則

    1:按功能分類的話:

    • xxx():表示該方法將繼續(xù)在已有的線程中執(zhí)行;

    • xxxAsync():表示將異步在線程池中執(zhí)行。

    • 異步執(zhí)行方法默認(rèn)一個(gè)參數(shù)的話任務(wù)是在 ForkJoinPool.commonPool() 線程池中執(zhí)行的,帶executor 參數(shù)的使用 executor線程池異步執(zhí)行。

    2:按邏輯和組織方式來分話(completableFuture 中大約有50個(gè)來方法)

    • 一種是 then 的邏輯,即前一個(gè)計(jì)算完成的時(shí)候調(diào)度后一個(gè)計(jì)算

    • 一種是 both 的邏輯,即等待兩個(gè)計(jì)算都完成之后執(zhí)行下一個(gè)計(jì)算,只要能組合一個(gè)和另一個(gè),我們就可以無限復(fù)用這個(gè) +1 的邏輯組合任意多的計(jì)算

    • 另一種是 either 的邏輯,即等待兩個(gè)計(jì)算的其中一個(gè)完成之后執(zhí)行下一個(gè)計(jì)算。注意這樣的計(jì)算可以說是非確定性的。因?yàn)楸唤M合的兩個(gè)計(jì)算中先觸發(fā)下一個(gè)計(jì)算執(zhí)行的那個(gè)會(huì)被作為前一個(gè)計(jì)算,而這兩個(gè)前置的計(jì)算到底哪一個(gè)先完成是不可預(yù)知的

    3:從依賴關(guān)系和出入?yún)?shù)類型區(qū)別,基本分為三類:

    • apply 字樣的方式意味著組合方式是 Function,即接受前一個(gè)計(jì)算的結(jié)果,應(yīng)用函數(shù)之后返回一個(gè)新的結(jié)果

    • accept 字樣的方式意味著組合方式是 Consumer,即接受前一個(gè)計(jì)算的結(jié)果,執(zhí)行消費(fèi)后不返回有意義的值

    • run 字樣的方式意味著組合方式是 Runnable,即忽略前一個(gè)計(jì)算的結(jié)果,僅等待它完成后執(zhí)行動(dòng)作
    其中出入?yún)?shù)主要有JDK8 Function,Consumer或Runnable三中函數(shù)型接口,每一種都決定了是怎么樣一種依賴關(guān)系,我有一篇文章詳細(xì)介紹了JDK8函數(shù)型接口用法,能有助理解completableFuture方法使用。
    http://m.tkk7.com/zzzlyr/articles/435611.html

    4:completableFuture 配合框架使用

      因?yàn)樽詮腏DK8以后增強(qiáng)了多線程的使用便捷程度:
    1:JDk8 的函數(shù)式接口和lambda表過式
    2:completableFuture 對(duì) Future 類的增強(qiáng)。
    這只是JDK 基礎(chǔ)包中的功能,現(xiàn)在大部分開發(fā)都在使用框架 java 現(xiàn)在基本上都在使用spring框架,因?yàn)镴DK基礎(chǔ)包中的功能還是不如框架使用方便,下邊文章詳細(xì)介紹 springboot中對(duì)JDK基礎(chǔ)包中多線程功能配置和使用。
    http://m.tkk7.com/zzzlyr/articles/435305.html



    posted @ 2020-07-23 19:29 為自己代言 閱讀(859) | 評(píng)論 (0)編輯 收藏

    2020年3月25日

         摘要: 如何在 Spring 使用@Async,@EnableAsync注釋進(jìn)行異步處理:異步處理適用那些與業(yè)務(wù)邏輯(橫切關(guān)注點(diǎn))不直接相關(guān)或者不作為其他業(yè)務(wù)邏輯輸入的部分,也可在分布式系統(tǒng)中解耦。*譯注:橫切關(guān)注點(diǎn)(cross-cutting concerns)指一些具有橫越多個(gè)模塊的行為,使用傳統(tǒng)的軟件開發(fā)方法不能夠達(dá)到有效模塊化的一類特殊關(guān)注點(diǎn)。*Spring 中,`@Async`注解可以標(biāo)記異步操...  閱讀全文

    posted @ 2020-03-25 20:19 為自己代言 閱讀(8105) | 評(píng)論 (0)編輯 收藏

    2018年12月10日

    或者按Shift+p公司生產(chǎn)服務(wù)上常常出現(xiàn) CPU 100% 問題,需要快速定位問題出現(xiàn)在那里,以下備注解決方法步驟:

    1: 工具:top方法:
    執(zhí)行top -c ,顯示進(jìn)程運(yùn)行信息列表
    鍵入P (大寫p),進(jìn)程按照CPU使用率排序  (輸入大寫P,則結(jié)果按CPU占用降序排序。輸入大寫M,結(jié)果按內(nèi)存占用降序排序。(注:大寫P可以在capslock狀態(tài)輸入p,或者按Shift+p)
    线ä¸?æ??å?¡CPU100%é—®é¢?å¿«é??å®?ä½?å®?æ??
    如上圖找出最耗CPU 進(jìn)程 10765
    統(tǒng)計(jì)信息區(qū)

    前五行是系統(tǒng)整體的統(tǒng)計(jì)信息。第一行是任務(wù)隊(duì)列信息,同 uptime 命令的執(zhí)行結(jié)果。其內(nèi)容如下:

    01:06:48當(dāng)前時(shí)間
    up 1:22系統(tǒng)運(yùn)行時(shí)間,格式為時(shí):分
    1 user當(dāng)前登錄用戶數(shù)
    load average: 0.06, 0.60, 0.48系統(tǒng)負(fù)載,即任務(wù)隊(duì)列的平均長度。
    三個(gè)數(shù)值分別為 1分鐘、5分鐘、15分鐘前到現(xiàn)在的平均值。

    步驟二:找出最耗CPU的線程
    1.    top -Hp 10765 顯示一個(gè)進(jìn)程的線程運(yùn)行信息列表
    2. 鍵入shift +p 線程按照CPU使用率降序排序
     步驟三: 把 10765 轉(zhuǎn)化成16進(jìn)制(因?yàn)槎褩J蔷€程id是十六進(jìn)制)
         命令: printf '%x' 10765   輸出結(jié)果:2a0d

    步驟四: 使用JVM命令  jstatck 
                jstack 10765 | grep '2a0d' -C5 --color     打印堆棧信息,通過id 過濾到線程的堆棧信息。


    以下是top 其它常用命令:

    附常用操作:

    top   //每隔5秒顯式所有進(jìn)程的資源占用情況
    top -d 2 //每隔2秒顯式所有進(jìn)程的資源占用情況
    top -c //每隔5秒顯式進(jìn)程的資源占用情況,并顯示進(jìn)程的命令行參數(shù)(默認(rèn)只有進(jìn)程名)
    top -p 1111 -p 6789//每隔5秒顯示pid是1111和pid是6789的兩個(gè)進(jìn)程的資源占用情況
    top -d 2 -c -p 1111//每隔2秒顯示pid是1111的進(jìn)程的資源使用情況,并顯式該進(jìn)程啟動(dòng)的命令行參數(shù)        

    posted @ 2018-12-10 15:59 為自己代言 閱讀(192) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲成色在线影院| 亚洲国产成人片在线观看无码| 亚洲成人网在线播放| 污污网站18禁在线永久免费观看| 久久亚洲国产成人影院网站| www在线观看免费视频| 亚洲精品无码成人片在线观看| 猫咪免费观看人成网站在线| 免费精品国产自产拍观看| 视频一区二区三区免费观看| 亚洲Av无码乱码在线观看性色| 一区免费在线观看| 亚洲人成77777在线播放网站| 最近免费中文字幕MV在线视频3| 亚洲AV无码成人网站久久精品大| 一区二区三区福利视频免费观看| 亚洲色图黄色小说| 妞干网免费视频在线观看| 老湿机一区午夜精品免费福利| 亚洲精品专区在线观看| 野花香在线视频免费观看大全| 久久久亚洲裙底偷窥综合| 欧洲乱码伦视频免费| 国产精品亚洲专区无码牛牛| 亚洲日韩人妻第一页| 华人在线精品免费观看| 亚洲国产av一区二区三区丶| 色www永久免费视频| h片在线播放免费高清| 亚洲2022国产成人精品无码区 | 亚洲成人午夜电影| 永久久久免费浮力影院| 久久久久久国产a免费观看不卡| 亚洲制服中文字幕第一区| 野花高清在线观看免费完整版中文 | 综合亚洲伊人午夜网| 免费A级毛片无码A∨中文字幕下载 | 免费一级毛suv好看的国产网站| 亚洲自偷自偷图片| 国产一卡二卡3卡四卡免费| 最好2018中文免费视频|