模拟多线程触发

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锁操作的更多相关文章

  1. (实例篇)php 使用redis锁限制并发访问类示例

    1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...

  2. php 使用redis锁限制并发访问类

    1.并发访问限制问题 对于一些需要限制同一个用户并发访问的场景,如果用户并发请求多次,而服务器处理没有加锁限制,用户则可以多次请求成功. 例如换领优惠券,如果用户同一时间并发提交换领码,在没有加锁限制 ...

  3. PHP Redis锁

    一.什么是 Redis Redis是由意大利人Salvatore Sanfilippo(网名:antirez)开发的一款内存高速缓存数据库 二.什么是 Redis 分布式锁 分布式锁其实可以理解为:控 ...

  4. PHP进阶与redis锁限制并发访问功能示例

    <?php /** * Redis锁操作类 * Date: 2017-06-30 * Author: fdipzone * Ver: 1.0 * * Func: * public lock 获取 ...

  5. 【连载】redis库存操作,分布式锁的四种实现方式[三]--基于Redis watch机制实现分布式锁

    一.redis的事务介绍 1. Redis保证一个事务中的所有命令要么都执行,要么都不执行.如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行.而一旦客户端发 ...

  6. php的redis 操作类,适用于单台或多台、多组redis服务器操作

    redis 操作类,包括单台或多台.多组redis服务器操作,适用于业务复杂.高性能要求的 php web 应用. redis.php: <?php /* redis 操作类,适用于单台或多台. ...

  7. 解锁redis锁的正确姿势

    解锁redis锁的正确姿势 redis是php的好朋友,在php写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为.这个时候我们就要用到锁.锁的方式有好几种,php不能在内存中用锁 ...

  8. redis锁机制介绍与实例

    转自:https://m.jb51.net/article/154421.htm 今天小编就为大家分享一篇关于redis锁机制介绍与实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要 ...

  9. 多线程并发问题解决之redis锁

    一 问题背景 我们做的是医疗信息化系统,在系统中一条患者信息对医院中当前科室中的所有诊断医生是可见的,当有一个诊断医生点击按钮处理该数据时,数据的状态发生了变化,其他的医生就不可以再处理此患者的数据了 ...

随机推荐

  1. idea如何打war包(不使用maven)

    用多了maven的小伙伴,应该快忘了怎么不用maven打war包了吧,我也快忘了,所以趁我还记得,赶紧记录下来,多年后,当我回忆起往事........ 而且网上的教程也太坑了吧,牛头不搭马嘴,这害死多 ...

  2. JS学习第一天

    JS的三种引入方式: 内联:在标签属性中引入javascript:js代码    <a href="javascript:("helloworld")"& ...

  3. Deep Learning-Based Document Modeling for Personality Detection from Text 阅读笔记

    文章目录 代码地址 1. 摘要 2. 方法综述 2.1 输入信息预处理 2.2 文档层面的格式特征提取 2.3 数据过滤 2.4 单词层面上的特征提取 2.5分类 3. 分类网络结构 3.1 步骤 3 ...

  4. Centos+Nginx部署Vue项目

    1.项目打包生成dist文件夹 在项目根目录下打开cmd窗口,输入命令 npm run build //生成dist文件夹 2.将dist文件夹上传到centos7 使用scp命令或者用远程连接工具将 ...

  5. try-catch-finally异常处理:

    java中三种实现多态的方案: 一:父类:普通类,普通方法: 子类:普通类,普通方法: 二:父类:抽象类,抽象方法: 子类:普通类,重写父类的抽象方法: 三:父类:接口类,抽象方法: 子类:普通类,实 ...

  6. 《Java从入门到失业》第二章:Java环境(二):JDK、JRE、JVM

    2.2JDK.JRE.JVM 在JDK的安装目录中,我们发现有一个目录jre(其实如果是下一步下一步安装的,在和JDK安装目录同级目录下,还会有一个jre目录).初学Java的同学,有时候搞不清楚这3 ...

  7. 2w字 + 40张图带你参透并发编程!

    并发历史 在计算机最早期的时候,没有操作系统,执行程序只需要一种方式,那就是从头到尾依次执行.任何资源都会为这个程序服务,在计算机使用某些资源时,其他资源就会空闲,就会存在 浪费资源 的情况. 这里说 ...

  8. SpringCloud简记_part2

    Zookeeper服务注册与发现 1)Eureka停止更新了,你怎么办? https://github.com/Netflix/eureka/wiki 2)SpringCloud整合Zookeeper ...

  9. JavaScript学习系列博客_24_JavaScript 原型对象

    原型(prototype) - 创建一个函数(所有函数)以后,解析器都会默认在函数中添加一个属性prototype prototype属性指向的是一个对象,这个对象我们称为原型对象. 创建一个函数My ...

  10. ceph 开启mgr balancer

    参考链接: mgr balancer模式探索及配置方法1 mgr balancer模式探索及配置方法2 1.ceph mgr module enable balancer [root@controll ...