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));
}
}