吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2708|回复: 1
收起左侧

[会员申请] 申请会员ID:生于忧患

[复制链接]
吾爱游客  发表于 2016-6-25 22:56



      申请会员ID:生于忧患


        邮箱:550084490@qq.com
        希望加入52pojie大家庭,今天浅谈下



              并发锁,希望管理员予以通过

    1:何为并发锁?并发锁有什么用?


    首先呢,我们在实际的业务中,肯定有一些交易类业务。举几个最的例子。
    NO1.一个商品库存只剩下十份,但是有一百个人在同时购买。那么后端的业务肯定是这样:检查商品库存、检查订单金额与余额/或直接第三方支付、完成订单并扣除库存。。。这个业务很常见,每个人都网购过,那么一百个人同时购买,会怎样呢?一百个人同时在检查库存,而每个人只买了一份,库存剩余十份,那么肯定会检查通过,走入第二步,第三步。最终导致库存为负数。

    NO2.交易类业务非常常见,某个交易要10块钱,而用户剩下20,按理来说可以买两份,可是用户来个并发,在某些特定的情况下说不定就买了几十份。正常的用户自然不会出问题,可是如果用户是职业BUG审计手,在交易的时候抓个包,终止这个包并保存协议,然后多线程发出这个包,那么可以导致几百次交易同时进行。然而后端的业务是:检查交易金额、检查用户余额、进行业务处理。然而几百个并发同时进行,这时候用户有20块钱,商品只需要10元,肯定是检查通过的,那么这写同时检查通过的就造成了多次交易,最终余额刷到负数。

    在这个业务基础上,有了并发锁的存在。通俗点讲。就是一个用户,只能同时进行一个交易。在这个交易的基础上,该用户的所有交易都要排队进行。

    synchronized (ZKLockUtil.class) {
                //进行业务处理
    }

    当然,这个也是锁,但这个锁不是并发锁,这个锁会锁住全系统所有用户,不能解决集群模式下的并发问题,而且这个锁效率极低。简单的说,在这个锁的前提下,如果有一百个用户,每个用户同时进行一百个交易,那么一万个统统排队;然而并发锁却非如此,一百个用户同时进行,每个用户的一百个交易再排队。

    类似的业务也只有在并发锁的模式下才是合理的。完善的。才能支持大用户,才能在集群模式下保证数据安全。

    2:并发锁如何能锁住,如何最合理

    并发锁要锁住有很多种方案,每种方案都有一定的适用性。

    NO1.
    synchronized (CacheFinal.class) {
                //进行业务处理
    }

    这个锁太牛逼了,单机部署绝对可以锁住,而且还能做到绝对安全。但是效率呢,效率呢,抢购、秒杀、抽奖你这个锁是在坑用户还是在坑老板,玩我么???


    NO2.
            //定义并发锁标志
            String key=CacheFinal.USER_INFO_KEY +userId;
            Boolean isRun=false;
            synchronized (CacheFinal.class) {
                isRun=(Boolean) CacheTimerHandler.getCache(key);
                if(isRun!=null&&isRun==true){
                    System.out.println("该业务正在执行,本次业务放弃。");
                    return "请勿进行重复操作";
                }
                CacheTimerHandler.addCache(key, true);
            }
            try {
                //进行业务操作
            } catch (Exception e) {
                e.printStackTrace();
            }finally{
                //移除执行标志
                CacheTimerHandler.removeCache(key);
            }

    这是一个基于缓存的并发锁,CacheTimerHandler是缓存操作类。比方说redis、memcached

    很多项目中是这样实现的并发锁,但是redis、memcached这些东西存在瓶颈,当内存被使用完,会不规则的释放一部分冷门资源,而如果这时候刚好释放了并发锁标志,用户进行并发情况下的交易操作,还是有出现数据安全的可能性的。不过一般使用缓存作为并发锁的项目,都有一个预估内存。也就是给缓存一个估值。确保缓存使用不会超过这个值。

    NO3.
            // 分布式锁
            InterProcessMutex lock = null;
            CuratorFramework client = null;
            try {
                client = DistributedNewLock.getClient(lockServer);
                // 用户锁
                lock = DistributedNewLock.getLock(client, lockKey);
                //获取锁许可证
                if (!lock.acquire(5 * 1000, TimeUnit.SECONDS)) {
                    return false;
                }
                //进行业务操作
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                closeLock(lock);
                closeClient(client);
            }

    这个锁,就比较专业了,zookeeper,本身更大的意义就是为了对并发锁做处理的。阿里巴巴为了方便对zookeeper进行操作,还专门封装了框架叫做dubbo,当然,以上代码用到的是Curator。所需JAR:curator-client-2.10.0.jar   curator-framework-2.10.0.jar   curator-recipes-2.10.0.jar


    当然,笔者在一个项目中,这样使用锁感觉很麻烦。

    于是笔者写了一个方法:



    调用:





    一行代码带锁调用,是不是很爽?

    以下贴上该工具类所有代码:

    package com.scrum.net.comm.util;
    import java.lang.reflect.Method;
    import java.util.concurrent.TimeUnit;

    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.recipes.locks.InterProcessMutex;
    import org.apache.log4j.Logger;

    import com.scrum.net.comm.zk.lock.DistributedNewLock;
    /**
    * @remark 并发锁方法调用工具类
    * @author 公子
    * @time 2016-03-11
    */
    public class ZKLockUtil {

        protected static final Logger logger = Logger.getLogger(ZKLockUtil.class);
       
        /**
         * 基于分布式锁反射调用方法
         * @param targeObj  目标对象
         * @param methodName 目标方法名
         * @param lockServer 并发锁服务器
         * @param lockKey 并发锁KEY
         * @param paras 方法参数
         * @return
         */
        public static Object invokMethod(Object targeObj, String methodName,
                String lockServer, String lockKey, Object... paras) {
            // 分布式锁
            InterProcessMutex lock = null;
            CuratorFramework client = null;
            try {
                client = DistributedNewLock.getClient(lockServer);
                // 用户锁
                lock = DistributedNewLock.getLock(client, lockKey);
                //寻找方法
                Method method=getTargeMethod(targeObj.getClass().getDeclaredMethods(), methodName, paras);
                if(ObjectUtil.hasNull(method)){
                    method=getTargeMethod(targeObj.getClass().getMethods(), methodName, paras);
                }
                if(ObjectUtil.hasNull(method)){
                    System.out.println("方法不存在:"+targeObj.getClass().getName()+"."+methodName);
                    return null;
                }
                //获取锁许可证
                if (!lock.acquire(5 * 1000, TimeUnit.SECONDS)) {
                    return false;
                }
                method.setAccessible(true);
                //执行方法
                return method.invoke(targeObj, paras);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放锁
                closeLock(lock);
                closeClient(client);
            }
            return null;
        }
        /**
         * 从对象中获取目标方法
         * @param methods 方法数组
         * @param methodName 方法名称
         * @param paras 参数列表
         * @return
         */
        private static Method getTargeMethod(Method []methods,String methodName,Object...paras){
            for (Method m:methods) {
                    if(isTargeMethod(m, methodName, paras)){
                        return m;
                    }
            }
            return null;
        }
        /**
         * 判断目标是否是当前方法
         * @param method 当前方法
         * @param methodName 目标方法名
         * @param paras 目标方法参数列表
         * @return
         */
        private static boolean isTargeMethod(Method method,String methodName,Object...paras){
            if(!method.getName().equals(methodName)){
                return false;
            }
            Class[] clas=method.getParameterTypes();
            if(ObjectUtil.isNullOrEmpty(clas)&&ObjectUtil.isNullOrEmpty(paras)){
                return true;
            }
            if(ObjectUtil.isNullOrEmpty(clas)||ObjectUtil.isNullOrEmpty(paras)){
                return false;
            }
            if(clas.length!=paras.length){
                return false;
            }
            for (int i=0;i             System.out.println(paras.getClass().getName());
                System.out.println(clas.getName());
                if(!(clas.getName().equals(paras.getClass().getName()))){
                    return false;
                }
            }
            return true;
        }
        //释放连接
        private static void closeClient(CuratorFramework client) {
            if (client != null) {
                DistributedNewLock.closeClient(client);
            }
        }
        //释放锁
        private static void closeLock(InterProcessMutex lock) {
            // 释放锁
            if (lock != null) {
                try {
                    lock.release();
                } catch (Exception e) {
                    logger.error("释放失败", e);
                }
            }
        }
    }

      感谢管理员耐心看完,望审核通过





发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2016-6-27 16:04
http://blog.51duobei.com/article_2.html 这个是你发布的?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 20:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表