redis锁操作
模拟多线程触发
package com.ws.controller; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock; @Api(value = "锁机制", description = "锁机制说明")
@RestController
public class LockController {
private static long count = 20;//黄牛
private CountDownLatch countDownLatch = new CountDownLatch(5); @Resource(name="redisLock")
private Lock lock; @ApiOperation(value="售票")
@RequestMapping(value = "/sale", method = RequestMethod.GET)
public Long sale() throws InterruptedException {
count = 20;
countDownLatch = new CountDownLatch(5); System.out.println("-------共20张票,分五个窗口开售-------");
new PlusThread().start();
new PlusThread().start();
new PlusThread().start();
new PlusThread().start();
new PlusThread().start();
return count;
} // 线程类模拟一个窗口买火车票
public class PlusThread extends Thread {
private int amount = 0;//抢多少张票 @Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始售票");
countDownLatch.countDown();
if (countDownLatch.getCount()==0){
System.out.println("----------售票结果------------------------------");
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
} while (count > 0) {
lock.lock();
try {
if (count > 0) {
//模拟卖票业务处理
amount++;
count--;
}
}finally{
lock.unlock();
} try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "售出"+ (amount) + "张票");
}
}
}
redis锁实现
package com.ws.lock; import com.enjoy.utils.FileUtils;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis; import javax.annotation.Resource;
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; @Service
public class RedisLock implements Lock { private static final String KEY = "LOCK_KEY"; @Resource
private JedisConnectionFactory factory; private ThreadLocal<String> local = new ThreadLocal<>(); @Override
//阻塞式的加锁
public void lock() {
//1.尝试加锁
if(tryLock()){
return;
}
//2.加锁失败,当前任务休眠一段时间
try {
Thread.sleep(10);//性能浪费
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.递归调用,再次去抢锁
lock();
} @Override
//阻塞式加锁,使用setNx命令返回OK的加锁成功,并生产随机值
public boolean tryLock() {
//产生随机值,标识本次锁编号
String uuid = UUID.randomUUID().toString();
Jedis jedis = (Jedis) factory.getConnection().getNativeConnection(); /**
* key:我们使用key来当锁
* uuid:唯一标识,这个锁是我加的,属于我
* NX:设入模式【SET_IF_NOT_EXIST】--仅当key不存在时,本语句的值才设入
* PX:给key加有效期
* 1000:有效时间为 1 秒
*/
String ret = jedis.set(KEY, uuid,"NX","PX",1000); //设值成功--抢到了锁
if("OK".equals(ret)){
local.set(uuid);//抢锁成功,把锁标识号记录入本线程--- Threadlocal
return true;
} //key值里面有了,我的uuid未能设入进去,抢锁失败
return false;
} //正确解锁方式
public void unlock() {
//读取lua脚本
String script = FileUtils.getScript("unlock.lua");
//获取redis的原始连接
Jedis jedis = (Jedis) factory.getConnection().getNativeConnection();
//通过原始连接连接redis执行lua脚本
jedis.eval(script, Arrays.asList(KEY), Arrays.asList(local.get()));
} //----------------------------------------------- @Override
public Condition newCondition() {
return null;
} @Override
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
return false;
} @Override
public void lockInterruptibly() throws InterruptedException {
} }
文件读取工具类
package com.ws.utils; import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader; public class FileUtils {
//无成员变量 --- 无状态
public static String getScript(String fileName){
String path = FileUtils.class.getClassLoader().getResource(fileName).getPath();
return readFileByLines(path);
} public static String readFileByLines(String fileName) {
FileInputStream file = null;
BufferedReader reader = null;
InputStreamReader inputFileReader = null;
String content = "";
String tempString = null;
try {
file = new FileInputStream(fileName);
inputFileReader = new InputStreamReader(file, "utf-8");
reader = new BufferedReader(inputFileReader);
// 一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
content += tempString;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return content;
} public static void main(String[] args) {
String path = FileUtils.class.getClassLoader().getResource("unlock.lua").getPath();
String script = FileUtils.readFileByLines(path);
System.out.println(script);
}
}
redis配置类
package com.ws.config; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig; @Configuration
public class RedisConfig { @Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(10);
jedisPoolConfig.setMaxTotal(10000);
return jedisPoolConfig;
} @Bean
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("192.168.42.111");
jedisConnectionFactory.setPort(6379);
jedisConnectionFactory.setPassword("12345678");
jedisConnectionFactory.setUsePool(true);
jedisConnectionFactory.setPoolConfig(jedisPoolConfig); return jedisConnectionFactory;
}
}
lua脚本
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
redis锁操作的更多相关文章
- (实例篇)php 使用redis锁限制并发访问类示例
1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...
- php 使用redis锁限制并发访问类
1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...
- PHP Redis锁
一.什么是 Redis Redis是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库 二.什么是 Redis 分布式锁 分布式锁其实可以理解为:控 ...
- PHP进阶与redis锁限制并发访问功能示例
<?php /** * Redis锁操作类 * Date: 2017-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[三]--基于Redis watch机制实现分布式锁
一.redis的事务介绍 1. Redis保证一个事务中的所有命令要么都执行,要么都不执行.如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行.而一旦客户端发 ...
- php的redis 操作类,适用于单台或多台、多组redis服务器操作
redis 操作类,包括单台或多台.多组redis服务器操作,适用于业务复杂.高性能要求的 php web 应用. redis.php: <?php /* redis 操作类,适用于单台或多台. ...
- 解锁redis锁的正确姿势
解锁redis锁的正确姿势 redis是php的好朋友,在php写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为.这个时候我们就要用到锁.锁的方式有好几种,php不能在内存中用锁 ...
- redis锁机制介绍与实例
转自:https://m.jb51.net/article/154421.htm 今天小编就为大家分享一篇关于redis锁机制介绍与实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要 ...
- 多线程并发问题解决之redis锁
一 问题背景 我们做的是医疗信息化系统,在系统中一条患者信息对医院中当前科室中的所有诊断医生是可见的,当有一个诊断医生点击按钮处理该数据时,数据的状态发生了变化,其他的医生就不可以再处理此患者的数据了 ...
随机推荐
- GitLab 后台修改用户密码
GitLab 后台修改用户密码 # 打开控制台 gitlab-rails console production # 找到用户,输入密码,确认密码,保存 user = User.find_by(user ...
- ElasticSearch 7.8.1集群搭建
通往集群的大门 集群由什么用? 高可用 高可用(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间.如果系统每运行100个时间 ...
- CVE-2020-0796“永恒之黑”漏洞复现
0x00 漏洞概述 Microsoft Server Message Block 3.1.1(SMBv3)协议在处理某些请求的方式中存在代码执行漏洞.攻击者可以精心构造数据包发送到SMB服务器,无需经 ...
- android.content.ActivityNotFoundException: No Activity found to handle Intent { (has extras) }
报错: 初始代码: @OnClick(R.id.include_top_iv_more) public void onViewClicked() { Intent intent_chat_set = ...
- SSM框架整合练习——一个简单的文章管理系统
使用SSM框架搭建的简易文章管理系统,实现了简单的增删改查功能. @ 目录 开发工具版本: 最终的项目结构 IDEA+Maven搭建项目骨架 1. 新建Maven项目: 2. 在新建的项目中添加所需要 ...
- python基础 Day5
python Day5 字典 其他数据类型的缺点 列表可以存储大量的数据,但是关联性不强. 列表的查询速度比较慢 其容器的数据类型为dict 其数据类型的分类 可变(不可哈希)的数据类型:list d ...
- AOP计算方法执行时长
AOP计算方法执行时长 依赖引入 <dependency> <groupId>org.springframework.boot</groupId> <arti ...
- neutron plugin 笔记
neutron-plugin 分为 core-plugin 和 service-plugin 两类 L2-L3称为core plugin,包含network.subnet.portL4-L7称为ser ...
- 2020.5.23 第三篇 Scrum冲刺博客
Team:银河超级无敌舰队 Project:招新通 项目冲刺集合贴:链接 目录 一.每日站立会议 二.项目燃尽图 三.签入记录 3.1 代码/文档签入记录 3.2 主要代码截图 3.3 程序运行截图 ...
- 问卷星的数据导入spss后变量乱码如何处理?
一般是字符编码问题.打开一个空的SPSS数据集,选择[编辑]-[选项]-[常规]-[数据和语法的字符编码].修改下当前的编码系统,原来是第一种就换成第二种,原来是第二种就换成第一种,打开一个数据再看看 ...