java處理高併發

1、使用SynChronize關鍵字處理

      在需要處理並發現象的方法處添加Synchronize關鍵字即可完成高併發的現象。

      優點:簡單、快捷

      缺點:並發現象數量巨大的情況下,訪問的時間延長

               

 

 

2、使用redis分佈式鎖處理高併發

    第一步:pom.xml中引入redis依賴

<!-- 引入redis依賴 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-redis</artifactId>
   <version>1.4.6.RELEASE</version>
</dependency>

     第二步:在application.yml中對redis進行配置

spring:
  redis:
    host: '127.0.0.1'
    password: '123456'
    port: 6379
    database: 0

第三步:書寫加鎖解鎖代碼

package com.ltj.personalweb.Utils;

import com.sun.org.apache.xpath.internal.operations.Bool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.StringUtils;

//redis解決高併發
@Component
@Slf4j
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加鎖
     * @param key                   已經拿到該鎖的唯一ID
     * @param value                 當前時間+超時時間(既是兩個時間的時間戳)
     * @return
     */
    public Boolean addLock(String key,String value){

        if(redisTemplate.opsForValue().setIfAbsent(key,value)){
            /**
             * setIfAbsent方法相當於redis執行命令setnx(set not exit)
             * 當該值不存在的情況下設置進去,否則不執行
             */
           return true;
        }
        //獲取當前鎖的時間戳
        String currentValue = redisTemplate.opsForValue().get(key);

        if(!StringUtils.isEmpty(currentValue)                                       //判斷當前獲取該鎖的時間戳是否不爲空
            &&Long.parseLong(currentValue) < System.currentTimeMillis()){           //判斷redis中存儲的值的當前時間戳是否小於當前系統的時間戳

            //獲取上一個鎖的時間戳值並設置時間戳的值
            String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
            if(!StringUtils.isEmpty(oldValue)                                       //判斷獲取的值是否爲空
                    && currentValue.equals(oldValue)){                              //判斷當前值獲取的值是否爲空
                return true;
            }

        }
        return false;

    }


    /**
     * 解鎖
     * @param key
     * @param value
     */
    public void unLock(String key,String value){

        try{
            //獲取當前值
            String currentValue = redisTemplate.opsForValue().get(key);

            if(!StringUtils.isEmpty(currentValue)
                    && value.equals(currentValue)){
                //刪除獲取的key值
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            log.error("redis分佈式解鎖異常,{}",e);
        }
    }
}

第五步:在適合的場景下面調用加鎖、解鎖的方法

package com.ltj.personalweb.controller;

import com.ltj.personalweb.Utils.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.omg.CORBA.TIMEOUT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 測試使用redis解決高併發
 */
@Controller
@Slf4j
public class RedisHighConCurrency {

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final Integer TIMEOUT = 10 * 1000;           //超時時間

    private static final String key = "hello";

    private static final Long currenttime = System.currentTimeMillis() + TIMEOUT;

    /**
     * 解決高並發現象
     */
    @RequestMapping("testConcurrency")
    public void solveHighConCurrency(){

        //加鎖
        Boolean bool = redisLock.addLock(key,String.valueOf(currenttime));
        if(!bool){
            //併發情況下、搶鎖失敗
            log.info("key爲:{}、value爲:{},搶鎖失敗,繼續加油!",key,currenttime);
            throw new RuntimeException();
        }


        /**
         * 
         *
         * 執行需求代碼
         *
         *
         */



        //解鎖
        redisLock.unLock(key,String.valueOf(currenttime));

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章