1 商品搶購
主要邏輯是:減庫存,記錄搶購成功的用戶
@RestController
public class DemoController {
@Resource
private StringRedisTemplate stringRedisTemplate;
private static final String GOODS_STOCK_KEY = "goods:001"; // 秒殺商品庫存
private static final String GOODS_USER_KEY = "users:001"; // 搶購成功的用戶列表
/**
* 在不加鎖的情況下,會發生超賣
*/
@GetMapping("/seckill")
public String seckill() {
int userId = (int) (Math.random() * 1000);
ValueOperations valueOps = stringRedisTemplate.opsForValue();
ListOperations listOps = stringRedisTemplate.opsForList();
int stock = Integer.parseInt(valueOps.get(GOODS_STOCK_KEY));
if (stock > 0) {
valueOps.decrement(GOODS_STOCK_KEY);
listOps.leftPush(GOODS_USER_KEY, String.valueOf(userId));
return "搶購成功";
} else {
return "商品已售罄";
}
}
/**
* 將多個命令打包成一個原子操作,利用redis單線程執行命令的特性,在不加鎖的情況下避免了資源競爭
*/
@GetMapping("/seckill_lua")
public String seckill_lua() {
int userId = (int) (Math.random() * 1000);
String script = "if tonumber(redis.call('get', KEYS[1])) > 0 then " +
"redis.call('decr', KEYS[1]); " +
"redis.call('lpush', KEYS[2], ARGV[1]); " +
"return 1; " +
"else " +
"return 0; " +
"end; ";
DefaultRedisScript redisScript = new DefaultRedisScript();
redisScript.setResultType(Long.class);
redisScript.setScriptText(script);
List keyList = Arrays.asList(GOODS_STOCK_KEY, GOODS_USER_KEY);
Long result = stringRedisTemplate.execute(redisScript, keyList, String.valueOf(userId));
if (result == 1) {
return "搶購成功";
} else {
return "商品已售罄";
}
}
}
2 多線程處理Excel導入
/**
* 多線程處理Excel導入
*
* PS:
* Executors返回的線程池對象的弊端如下:
* (1) FixedThreadPool和SingleThreadPool: 允許的請求隊列長度爲Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM。
* (2) CachedThreadPool: 允許的創建線程數量爲Integer.MAX_VALUE,可能會創建大量的線程,從而導致OOM。
*/
@PostMapping
public void excelImport() throws InterruptedException {
// 待處理的數據(比如:從Excel中讀取的數據)
List dataList = new ArrayList();
// 多線程處理
ExecutorService executorService = Executors.newFixedThreadPool(5);
CountDownLatch countDownLatch = new CountDownLatch(dataList.size());
for (Object obj : dataList) {
executorService.submit(new Runnable() {
@Override
public void run() {
try {
} catch (Exception ex) {
} finally {
countDownLatch.countDown();
}
}
});
}
countDownLatch.await(30, TimeUnit.SECONDS);
// 後續執行
// 返回結果
}