免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
手把手教你 SpringBoot 分布式鎖的實(shí)現(xiàn)

你知道的越多,不知道的就越多,業(yè)余的像一棵小草!

你來(lái),我們一起精進(jìn)!你不來(lái),我和你的競(jìng)爭(zhēng)對(duì)手一起精進(jìn)!

編輯:業(yè)余草

來(lái)源:https://urlify.cn/632yIv

推薦:https://www.xttblog.com/?p=5035

前言

前段時(shí)間面試了一個(gè)高級(jí)程序員,問(wèn)他了一些分布式鎖的知識(shí),回答的還不錯(cuò)。后來(lái)進(jìn)了我們的團(tuán)隊(duì),剛好讓他接手一個(gè)新項(xiàng)目,需要用到分布式鎖,我說(shuō)這是你的強(qiáng)項(xiàng),你來(lái)實(shí)現(xiàn)。

誰(shuí)知,項(xiàng)目上線后,各種問(wèn)題接連爆發(fā)出來(lái)。后來(lái)我找他談話,主要是說(shuō),千萬(wàn)不要重復(fù)造輪子,直接吧 A 項(xiàng)目中的 Redisson 用法實(shí)現(xiàn)復(fù)制過(guò)來(lái)一份不就行了,干嘛非要自己搞一套,還搞出問(wèn)題。。。

今天,我們一起來(lái)手把手來(lái)實(shí)現(xiàn)一個(gè)高效的 SpringBoot 分布式鎖!本文通過(guò) Spring Boot 整合 redisson 來(lái)實(shí)現(xiàn)分布式鎖,并結(jié)合 demo 測(cè)試結(jié)果。

分析設(shè)計(jì)要點(diǎn)

當(dāng)我們?cè)谠O(shè)計(jì)分布式鎖的時(shí)候,我們應(yīng)該考慮分布式鎖至少要滿足的一些條件,同時(shí)考慮如何高效的設(shè)計(jì)分布式鎖,這里我認(rèn)為以下幾點(diǎn)是必須要考慮的。

1、互斥

在分布式高并發(fā)的條件下,我們最需要保證,同一時(shí)刻只能有一個(gè)線程獲得鎖,這是最基本的一點(diǎn)。

2、防止死鎖

在分布式高并發(fā)的條件下,比如有個(gè)線程獲得鎖的同時(shí),還沒(méi)有來(lái)得及去釋放鎖,就因?yàn)橄到y(tǒng)故障或者其它原因使它無(wú)法執(zhí)行釋放鎖的命令,導(dǎo)致其它線程都無(wú)法獲得鎖,造成死鎖。

所以分布式非常有必要設(shè)置鎖的有效時(shí)間,確保系統(tǒng)出現(xiàn)故障后,在一定時(shí)間內(nèi)能夠主動(dòng)去釋放鎖,避免造成死鎖的情況。

3、性能

對(duì)于訪問(wèn)量大的共享資源,需要考慮減少鎖等待的時(shí)間,避免導(dǎo)致大量線程阻塞。

所以在鎖的設(shè)計(jì)時(shí),需要考慮兩點(diǎn)。

1、鎖的顆粒度要盡量小。比如你要通過(guò)鎖來(lái)減庫(kù)存,那這個(gè)鎖的名稱你可以設(shè)置成是商品的ID,而不是任取名稱。這樣這個(gè)鎖只對(duì)當(dāng)前商品有效,鎖的顆粒度小。

2、鎖的范圍盡量要小。比如只要鎖2行代碼就可以解決問(wèn)題的,那就不要去鎖10行代碼了。

4、重入

我們知道ReentrantLock是可重入鎖,那它的特點(diǎn)就是:同一個(gè)線程可以重復(fù)拿到同一個(gè)資源的鎖。重入鎖非常有利于資源的高效利用。關(guān)于這點(diǎn)之后會(huì)做演示。

針對(duì)以上Redisson都能很好的滿足,下面就來(lái)使用它。

首先看下常規(guī)Redis鎖的處理圖

代碼實(shí)現(xiàn)
添加依賴
  1. <!--redis-->

  2. <dependency>

    1. <groupId>org.springframework.boot</groupId>

    2. <artifactId>spring-boot-starter-data-redis</artifactId>

  3. </dependency>

  4. <!--redisson-->

  5. <dependency>

    1. <groupId>org.redisson</groupId>

    2. <artifactId>redisson-spring-boot-starter</artifactId>

    3. <version>3.10.6</version>

  6. </dependency>

配置信息

  1. spring:

  2. # redis

  3. redis:

  4. host: 47.103.5.190

  5. port: 6379

  6. jedis:

  7. pool:

  8. # 連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制)

  9. max-active: 100

  10. # 連接池中的最小空閑連接

  11. max-idle: 10

  12. # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制)

  13. max-wait: -1

  14. # 連接超時(shí)時(shí)間(毫秒)

  15. timeout: 5000

  16. #默認(rèn)是索引為0的數(shù)據(jù)庫(kù)

  17. database: 0

配置類

  1. /**

  2. * redisson 配置,下面是單節(jié)點(diǎn)配置:

  3. *

  4. * @author gourd

  5. */

  6. @Configuration

  7. publicclassRedissonConfig{

  8. @Value('${spring.redis.host}')

  9. privateString host;

  10. @Value('${spring.redis.port}')

  11. privateString port;

  12. @Value('${spring.redis.password:}')

  13. privateString password;

  14. @Bean

  15. publicRedissonClient redissonClient() {

  16. Config config = newConfig();

  17. //單節(jié)點(diǎn)

  18. config.useSingleServer().setAddress('redis://'+ host + ':'+ port);

  19. if(StringUtils.isEmpty(password)) {

  20. config.useSingleServer().setPassword(null);

  21. } else{

  22. config.useSingleServer().setPassword(password);

  23. }

  24. //添加主從配置

  25. // config.useMasterSlaveServers().setMasterAddress('').setPassword('').addSlaveAddress(new String[]{'',''});

  26. // 集群模式配置 setScanInterval()掃描間隔時(shí)間,單位是毫秒, //可以用'rediss://'來(lái)啟用SSL連接

  27. // config.useClusterServers().setScanInterval(2000).addNodeAddress('redis://127.0.0.1:7000', 'redis://127.0.0.1:7001').addNodeAddress('redis://127.0.0.1:7002');

  28. returnRedisson.create(config);

  29. }

  30. }

Redisson 工具類

  1. /**

  2. * redis分布式鎖幫助類

  3. *

  4. * @author gourd

  5. *

  6. */

  7. publicclassRedisLockUtil{

  8. privatestaticDistributedLocker distributedLocker = SpringContextHolder.getBean('distributedLocker',DistributedLocker.class);

  9. /**

  10. * 加鎖

  11. * @param lockKey

  12. * @return

  13. */

  14. publicstaticRLocklock(String lockKey) {

  15. return distributedLocker.lock(lockKey);

  16. }

  17. /**

  18. * 釋放鎖

  19. * @param lockKey

  20. */

  21. publicstaticvoid unlock(String lockKey) {

  22. distributedLocker.unlock(lockKey);

  23. }

  24. /**

  25. * 釋放鎖

  26. * @param lock

  27. */

  28. publicstaticvoid unlock(RLocklock) {

  29. distributedLocker.unlock(lock);

  30. }

  31. /**

  32. * 帶超時(shí)的鎖

  33. * @param lockKey

  34. * @param timeout 超時(shí)時(shí)間 單位:秒

  35. */

  36. publicstaticRLocklock(String lockKey, int timeout) {

  37. return distributedLocker.lock(lockKey, timeout);

  38. }

  39. /**

  40. * 帶超時(shí)的鎖

  41. * @param lockKey

  42. * @param unit 時(shí)間單位

  43. * @param timeout 超時(shí)時(shí)間

  44. */

  45. publicstaticRLocklock(String lockKey, int timeout,TimeUnit unit ) {

  46. return distributedLocker.lock(lockKey, unit, timeout);

  47. }

  48. /**

  49. * 嘗試獲取鎖

  50. * @param lockKey

  51. * @param waitTime 最多等待時(shí)間

  52. * @param leaseTime 上鎖后自動(dòng)釋放鎖時(shí)間

  53. * @return

  54. */

  55. publicstaticboolean tryLock(String lockKey, int waitTime, int leaseTime) {

  56. return distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime);

  57. }

  58. /**

  59. * 嘗試獲取鎖

  60. * @param lockKey

  61. * @param unit 時(shí)間單位

  62. * @param waitTime 最多等待時(shí)間

  63. * @param leaseTime 上鎖后自動(dòng)釋放鎖時(shí)間

  64. * @return

  65. */

  66. publicstaticboolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {

  67. return distributedLocker.tryLock(lockKey, unit, waitTime, leaseTime);

  68. }

  69. /**

  70. * 獲取計(jì)數(shù)器

  71. *

  72. * @param name

  73. * @return

  74. */

  75. publicstaticRCountDownLatch getCountDownLatch(String name){

  76. return distributedLocker.getCountDownLatch(name);

  77. }

  78. /**

  79. * 獲取信號(hào)量

  80. *

  81. * @param name

  82. * @return

  83. */

  84. publicstaticRSemaphore getSemaphore(String name){

  85. return distributedLocker.getSemaphore(name);

  86. }

  87. }

底層封裝

  1. /**

  2. * @author gourd

  3. */

  4. publicinterfaceDistributedLocker{

  5. RLocklock(String lockKey);

  6. RLocklock(String lockKey, int timeout);

  7. RLocklock(String lockKey, TimeUnit unit, int timeout);

  8. boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime);

  9. void unlock(String lockKey);

  10. void unlock(RLocklock);

  11. }

  12. /**

  13. * @author gourd

  14. */

  15. @Component

  16. publicclassRedisDistributedLockerimplementsDistributedLocker{

  17. @Autowired

  18. privateRedissonClient redissonClient;

  19. @Override

  20. publicRLocklock(String lockKey) {

  21. RLocklock= redissonClient.getLock(lockKey);

  22. lock.lock();

  23. returnlock;

  24. }

  25. @Override

  26. publicRLocklock(String lockKey, int leaseTime) {

  27. RLocklock= redissonClient.getLock(lockKey);

  28. lock.lock(leaseTime, TimeUnit.SECONDS);

  29. returnlock;

  30. }

  31. @Override

  32. publicRLocklock(String lockKey, TimeUnit unit ,int timeout) {

  33. RLocklock= redissonClient.getLock(lockKey);

  34. lock.lock(timeout, unit);

  35. returnlock;

  36. }

  37. @Override

  38. publicboolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {

  39. RLocklock= redissonClient.getLock(lockKey);

  40. try{

  41. returnlock.tryLock(waitTime, leaseTime, unit);

  42. } catch(InterruptedException e) {

  43. returnfalse;

  44. }

  45. }

  46. @Override

  47. publicvoid unlock(String lockKey) {

  48. RLocklock= redissonClient.getLock(lockKey);

  49. lock.unlock();

  50. }

  51. @Override

  52. publicvoid unlock(RLocklock) {

  53. lock.unlock();

  54. }

  55. }


測(cè)試
模擬并發(fā)測(cè)試
  1. /**

  2. * redis分布式鎖控制器

  3. * @author gourd

  4. * @since 2019-07-30

  5. */

  6. @RestController

  7. @Api(tags = 'redisson', description = 'redis分布式鎖控制器')

  8. @RequestMapping('/redisson')

  9. @Slf4j

  10. publicclassRedissonLockController{

  11. /**

  12. * 鎖測(cè)試共享變量

  13. */

  14. privateInteger lockCount = 10;

  15. /**

  16. * 無(wú)鎖測(cè)試共享變量

  17. */

  18. privateInteger count = 10;

  19. /**

  20. * 模擬線程數(shù)

  21. */

  22. privatestaticint threadNum = 10;

  23. /**

  24. * 模擬并發(fā)測(cè)試加鎖和不加鎖

  25. * @return

  26. */

  27. @GetMapping('/test')

  28. @ApiOperation(value = '模擬并發(fā)測(cè)試加鎖和不加鎖')

  29. publicvoidlock(){

  30. // 計(jì)數(shù)器

  31. finalCountDownLatch countDownLatch = newCountDownLatch(1);

  32. for(int i = 0; i < threadNum; i ++) {

  33. MyRunnable myRunnable = newMyRunnable(countDownLatch);

  34. Thread myThread = newThread(myRunnable);

  35. myThread.start();

  36. }

  37. // 釋放所有線程

  38. countDownLatch.countDown();

  39. }

  40. /**

  41. * 加鎖測(cè)試

  42. */

  43. privatevoid testLockCount() {

  44. String lockKey = 'lock-test';

  45. try{

  46. // 加鎖,設(shè)置超時(shí)時(shí)間2s

  47. RedisLockUtil.lock(lockKey,2, TimeUnit.SECONDS);

  48. lockCount--;

  49. log.info('lockCount值:'+lockCount);

  50. }catch(Exception e){

  51. log.error(e.getMessage(),e);

  52. }finally{

  53. // 釋放鎖

  54. RedisLockUtil.unlock(lockKey);

  55. }

  56. }

  57. /**

  58. * 無(wú)鎖測(cè)試

  59. */

  60. privatevoid testCount() {

  61. count--;

  62. log.info('count值:'+count);

  63. }

  64. publicclassMyRunnableimplementsRunnable{

  65. /**

  66. * 計(jì)數(shù)器

  67. */

  68. finalCountDownLatch countDownLatch;

  69. publicMyRunnable(CountDownLatch countDownLatch) {

  70. this.countDownLatch = countDownLatch;

  71. }

  72. @Override

  73. publicvoid run() {

  74. try{

  75. // 阻塞當(dāng)前線程,直到計(jì)時(shí)器的值為0

  76. countDownLatch.await();

  77. } catch(InterruptedException e) {

  78. log.error(e.getMessage(),e);

  79. }

  80. // 無(wú)鎖操作

  81. testCount();

  82. // 加鎖操作

  83. testLockCount();

  84. }

  85. }

  86. }

調(diào)用接口后打印值:

測(cè)試結(jié)果
根據(jù)打印結(jié)果可以明顯看到,未加鎖的 count-- 后值是亂序的,而加鎖后的結(jié)果和我們預(yù)期的一樣。
本文只是實(shí)戰(zhàn)項(xiàng)目中復(fù)制出來(lái)的部分代碼,實(shí)際使用中封裝成了 jar,內(nèi)部系統(tǒng)只需要引用即可。最后,希望對(duì)大家有幫助。如有錯(cuò)誤之處,歡迎指正!

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
AP模式(Redis)的分布式鎖分析以及實(shí)現(xiàn)
幾行代碼,搞定 SpringBoot 接口惡意刷新和暴力請(qǐng)求!
不用找了,基于 Redis 的分布式鎖實(shí)戰(zhàn)來(lái)了!
8 種方案解決重復(fù)提交問(wèn)題,總有一種方案適合你!
jedisLock—redis分布式鎖實(shí)現(xiàn)
Jedis分布式鎖實(shí)現(xiàn)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服