zoukankan      html  css  js  c++  java
  • 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) + "张票");
            }
        }
    }
    View Code

     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 {
        }
    
    }
    View Code

    文件读取工具类

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

    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;
        }
    }
    View Code

     lua脚本

    if redis.call("get",KEYS[1]) == ARGV[1] then 
        return redis.call("del",KEYS[1]) 
    else 
        return 0 
    end
    View Code
  • 相关阅读:
    OpenStack 对接 Ceph
    《Netty权威指南》(二)NIO 入门
    《Netty权威指南》(一)走进 Java NIO
    进程间通信 IPC(Inter-Process Communication)
    CentOS7 下安装 iSCSI Target(tgt) ,使用 Ceph rbd
    CentOS7 下编译安装 Samba,什么是 SMB/CIFS 协议
    《Netty权威指南》目录
    CentOS7 下安装 NFS,Linux/Windows 作为客户端
    数据结构汇总
    Ceph 块设备
  • 原文地址:https://www.cnblogs.com/Soy-technology/p/11817370.html
Copyright © 2011-2022 走看看