乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      手把手教你 SpringBoot 分布式鎖的實現(xiàn)

       鷹兔牛熊眼 2020-06-27

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

      你來,我們一起精進(jìn)!你不來,我和你的競爭對手一起精進(jìn)!

      編輯:業(yè)余草

      來源:https:///632yIv

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

      前言

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

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

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

      分析設(shè)計要點

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

      1、互斥

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

      2、防止死鎖

      在分布式高并發(fā)的條件下,比如有個線程獲得鎖的同時,還沒有來得及去釋放鎖,就因為系統(tǒng)故障或者其它原因使它無法執(zhí)行釋放鎖的命令,導(dǎo)致其它線程都無法獲得鎖,造成死鎖。

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

      3、性能

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

      所以在鎖的設(shè)計時,需要考慮兩點。

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

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

      4、重入

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

      針對以上Redisson都能很好的滿足,下面就來使用它。

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

      代碼實現(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ù)值表示沒有限制)

      9. max-active: 100

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

      11. max-idle: 10

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

      13. max-wait: -1

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

      15. timeout: 5000

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

      17. database: 0

      配置類

      1. /**

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

      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é)點

      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()掃描間隔時間,單位是毫秒, //可以用'rediss://'來啟用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. * 帶超時的鎖

      33. * @param lockKey

      34. * @param timeout 超時時間 單位:秒

      35. */

      36. publicstaticRLocklock(String lockKey, int timeout) {

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

      38. }

      39. /**

      40. * 帶超時的鎖

      41. * @param lockKey

      42. * @param unit 時間單位

      43. * @param timeout 超時時間

      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 最多等待時間

      52. * @param leaseTime 上鎖后自動釋放鎖時間

      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 時間單位

      62. * @param waitTime 最多等待時間

      63. * @param leaseTime 上鎖后自動釋放鎖時間

      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. * 獲取計數(shù)器

      71. *

      72. * @param name

      73. * @return

      74. */

      75. publicstaticRCountDownLatch getCountDownLatch(String name){

      76. return distributedLocker.getCountDownLatch(name);

      77. }

      78. /**

      79. * 獲取信號量

      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. }


      測試
      模擬并發(fā)測試
      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. * 鎖測試共享變量

      13. */

      14. privateInteger lockCount = 10;

      15. /**

      16. * 無鎖測試共享變量

      17. */

      18. privateInteger count = 10;

      19. /**

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

      21. */

      22. privatestaticint threadNum = 10;

      23. /**

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

      25. * @return

      26. */

      27. @GetMapping('/test')

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

      29. publicvoidlock(){

      30. // 計數(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. * 加鎖測試

      42. */

      43. privatevoid testLockCount() {

      44. String lockKey = 'lock-test';

      45. try{

      46. // 加鎖,設(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. * 無鎖測試

      59. */

      60. privatevoid testCount() {

      61. count--;

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

      63. }

      64. publicclassMyRunnableimplementsRunnable{

      65. /**

      66. * 計數(shù)器

      67. */

      68. finalCountDownLatch countDownLatch;

      69. publicMyRunnable(CountDownLatch countDownLatch) {

      70. this.countDownLatch = countDownLatch;

      71. }

      72. @Override

      73. publicvoid run() {

      74. try{

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

      76. countDownLatch.await();

      77. } catch(InterruptedException e) {

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

      79. }

      80. // 無鎖操作

      81. testCount();

      82. // 加鎖操作

      83. testLockCount();

      84. }

      85. }

      86. }

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

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

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多