精华内容
下载资源
问答
  • 加锁

    2016-04-18 13:36:48
    Linu加锁

    a. 加锁定义 

    b. Linux有几种加锁,什么情况下会加锁

    1自旋锁

    2读写锁

    3RCU锁

    当有多个工作线程要同时对一个文件进行写操作时,如果不对该文件进行加锁就可能会因误操作引起一系列的问题,解决这个问题可以用文件加锁来进行保护。

    c. Linux不同的锁 定义 和 区别

    1:自旋锁  不用睡眠,只是自旋,没有考虑到数据的客观特殊类型以及操作类型

    2:读写锁:读时不能写,写时不能读,任意时刻只允许一个线程进行写,各写线程需要根据一定的顺序进行写。

    3:RCU锁

    d. 代码中如何体现加锁,如何实现加锁的(简述)

    展开全文
  • 并发编程经历:同步加锁之业务锁

    万次阅读 多人点赞 2019-07-31 18:37:55
    加锁逻辑就是锁名和人直接挂钩(就是锁名里有可以直接区分人的字段),通过执行sql:select get_lock(#锁名#, 0) as tolock;来获取数据库锁,如果获取成功,返回1。这里还去获取了一下行锁,获取的行锁它锁住的是venus...

    业务锁

    在处理并发问题时,很多情况下需要用到业务锁来达到按照某个维度同步执行业务块。

    例子:

     

    @Override
    @Transactional(rollbackFor = Exception.class, noRollbackFor = TerminateException.class)
    public ApplyDO submitApply(ApplyDOapplyDO) {
            LockResultEnum lockResultEnum =null;
            String lockName = new StringBuffer().append(applyDO.getSite()).append("_").append(applyDO.getSiteMemId()).toString();
            try {
                //加锁
                lockResultEnum = lockManager.getLock(lockName, LockTypeEnum.APPLY_LOCK.getCode());
                if (LockResultEnum.没有获取到锁.equals(lockResultEnum)){
                    throw new BizException(ErrorCode.LOCK_FAIL);
                }
                …
                returnapplyDO;
            } catch (TerminateExceptione) {
                throwe;
            } catch (BizExceptione) {
                throw new BizException(e.getErrorCode(),e);
            } catch (Exceptione) {
                throw new BizException(ErrorCode.GENERIC_ERROR,e);
            } finally {
                //释放锁
                lockManager.releaseLock(lockName, LockTypeEnum.APPLY_LOCK.getCode(),lockResultEnum);
            }
    }

     

     

     

    LockManager的getLock方法实现如下:

     

    @Override
    public LockResultEnum getLock(StringlockName,StringlockType){
            if(StringUtil.isEmpty(lockName)){
                LOG.error("getLock()参数为空,param:" +lockName);
                throw new BizException(ErrorCode.ILLEGAL_ARGUMENT,"参数为空!");
               
            }
            //只是生成一个数据库锁名,纯粹的字符串拼接过程
            String lockName_ = getDBLockName(lockName,lockType);
            booleanisGetDbLocked =lockDao.getDbLock(lockName_);
            if (isGetDbLocked) {
                LockDO lock = lockDao.getRowLockByName(lockName);
                if (lock !=null){
                    return LockResultEnum.获取锁成功;
                } else {
                    return LockResultEnum.仅数据库锁;
                }
            } else {
                LOG.warn("获取锁【" +lockName_+"】失败");
                return LockResultEnum.没有获取到锁;
            }
    }

     

     

     

    LockManager的releaseLock方法实现如下:

     

    @Override
    public void releaseLock(StringlockName,StringlockType,LockResultEnumlockResultEnum) {
            String lockName_ = getDBLockName(lockName,lockType);
            if (StringUtil.isEmpty(lockName)) {
                LOG.error("releaseLock()参数为空,lockName:{}",lockName);
                throw new BizException(ErrorCode.ILLEGAL_ARGUMENT,"参数为空!");
            }
            if (LockResultEnum.获取锁成功.equals(lockResultEnum)|| LockResultEnum.仅数据库锁.equals(lockResultEnum)) {
                booleanisReleased =lockDao.releaseDbLock(lockName_);
                if (!isReleased) {
                    LOG.warn("释放锁【" +lockName_+"】失败");
                }
            } else {
                LOG.debug("不需要释放锁【" +lockName_+"】");
            }
     }

     

     

     

    LockDao的实现如下:

     

    @Override
    public boolean getDbLock(String lockCode){
            Long lock = (Long)super.getSqlMapClientTemplate().queryForObject("LockDO.getLockDbByCode",lockCode);
            booleanresult = (lock !=null&&lock.longValue()== 1) ? true:false;
            returnresult;
    }
        @Override
        public boolean releaseDbLock(String lockCode) {
            Long lock = (Long)super.getSqlMapClientTemplate().queryForObject("LockDO.releaseLockDbByCode",lockCode);
            booleanresult = (lock !=null&&lock.longValue()== 1) ? true:false;
            returnresult;
        }
        @Override
        public LockDO getRowLockByName(Stringname) {
           return (LockDO)super.getSqlMapClientTemplate().queryForObject("LockDO.selectForUpdateByLockName",name);
    }

     

     

     

     

     

    LockDao对应sqlMap文件里的执行sql如下:

     

    <selectid="selectForUpdateByLockName"resultMap="jobLockMap" parameterClass="java.lang.String" >
            select
                   ID, NAME, REMARK, IS_ENABLED
              from VENUS_LOCK
             where NAME = #value# and  IS_ENABLED = 'y'
            FOR UPDATE
      </select>
           <!-- 通过指定的代码取得操作数据锁-->
       <selectid="getLockDbByCode"resultClass="java.lang.Long"parameterClass="string">
            <![CDATA[
                select get_lock(#value#, 0) as tolock;
            ]]>
       </select>
       <!-- 通过指定的代码释放操作数据锁-->
       <selectid="releaseLockDbByCode"resultClass="java.lang.Long"parameterClass="string">
            <![CDATA[
                select release_lock(#value#) as torelease;
            ]]>
        </select>

     

     

     

    通过以上代码可以很清楚的看出原理了。贷款申请提交时,为了防止一个人同时提交多笔,要按照以人维度进行业务锁的加锁处理。加锁逻辑就是锁名和人直接挂钩(就是锁名里有可以直接区分人的字段),通过执行sql:select get_lock(#锁名#, 0) as tolock;来获取数据库锁,如果获取成功,返回1。这里还去获取了一下行锁,获取的行锁它锁住的是venus_lock表的符合where条件的那些行,执行sql: select ID, NAME, REMARK,IS_ENABLED from VENUS_LOCK where NAME = #锁名#and  IS_ENABLED = 'y' FOR UPDATE;这里行锁是否获取成功其实都没有关系。获取到锁之后就可以执行业务逻辑了,执行完一定要释放锁,执行sql:select release_lock(#锁名#) as torelease;为了保证释放锁操作一定执行,一般在finally子句中执行它即可。通过以上的步骤,当一个人同时申请多笔时,锁名是一样的,所以获取到锁后返回值就是1、2、3…具体看你是第几个获取的了,只有第一个获取的返回值是1,从lockDao .getDbLock里的booleanresult = (lock !=null&&lock.longValue()== 1) ? true:false;就可以看出,只有第一个可以执行业务逻辑,其他就认为是没有获取到锁而抛出异常终止执行:if (LockResultEnum.没有获取到锁.equals(lockResultEnum)){thrownewBizException(ErrorCode.LOCK_FAIL); }

     

    还有一个例子:

    下面的是任务分发器,它实现了Runnable接口,在任务分发器执行时会去获取各种异步任务类型的待执行任务列表,这里也用到了业务锁,调用的和上面的一样都是lockManager.getLock(...)方法。

     

    public class JobDispatcher implements Runnable {
        private static final Logger LOG                 = LoggerFactory.getLogger("applyCenterJobLog");
        /** 守护线程名称 */
        private String              name;
        /** 一天秒数 */
        private static final long   ONE_DAY_SEC         = 24 * 60 * 60;
        /** 线程池队列长度 */
        private int                 queueSize           = 5;
        /** 初始处理线程数 */
        private int                 coreSize            = 5;
        /** 最大处理线程数 */
        private int                 maxSize             = 5;
        /** 空闲线程最大闲置时间 */
        private long                keepAliveTime       = ONE_DAY_SEC;
        /** 线程池接收新任务阀值 */
        private int                 hungrySize          = 2;
        /** 分发器运行状态标记 */
        private boolean             isRunning           = true;
        /** 无命令处理时休息时常(毫秒) */
        private long                noCmdSleepMillis    = 1000;
        /** 出现系统异常时休息时常(毫秒),防止把系统拖垮 */
        private long                errorCmdSleepMillis = 10000;
    
    
        private JobManager          jobManager;
        /** handler产生工厂类 */
        private JobHandlerFactory   jobHandlerFactory;
    
    
        private List<String>        jobTypeList;
    
    
        /**
         * spring init
         */
        public void init() {
            LOG.info("分发器【" + name + "】init!!!!!");
            jobTypeList = jobHandlerFactory.getJobTypeList();
        }
    
    
        /**
         * spring destroy
         */
        public void destroy() {
            LOG.warn("收到分发器【" + name + "】停止通知!!!!!");
            isRunning = false;
        }
    
    
        @Override
        public void run() {
            LOG.info("分发器【" + name + "】启动ing...");
            BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(queueSize);
            ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, maxSize, keepAliveTime, TimeUnit.SECONDS, queue);
            while (isRunning) {
                try {
                    int i = 0;
                    if (queue.size() < hungrySize) {
                        for (String jobType : jobTypeList) {
                            List<JobDO> jobDOList = jobManager.assignJob(jobType, queueSize - queue.size());
                            for (JobDO jobDO : jobDOList) {
                                i++;
                                JobHandler<JobDO> tmpJobHandler = jobHandlerFactory.getHandler(jobDO);
                                ExecuteJobThread<JobDO> executeCmdThread = new ExecuteJobThread<JobDO>(jobDO, tmpJobHandler);
                                executor.execute(executeCmdThread);
                            }
                        }
                    } else {
                        ThreadUtil.sleep(noCmdSleepMillis, LOG);
                    }
                    if (i == 0) {
                        ThreadUtil.sleep(noCmdSleepMillis, LOG);
                    } else {
                        i = 0;
                    }
                } catch (Exception e) {
                    LOG.error("dispacher 调度异常" + e.getMessage(), e);
                    ThreadUtil.sleep(errorCmdSleepMillis, LOG);
                }
            }
            executor.shutdown();
        }
    
    
        /**
         * 执行分发
         */
        public void dispatcher() {
            Thread thread = new Thread(this);
            isRunning = true;
            thread.start();
        }
    ...//一些set方法
    }

     

     

     

     

     

    jobManager的assignJob方法如下:

     

    public List<JobDO> assignJob(String jobType, int jobNum) {
            if (StringUtil.isBlank(jobType) || jobNum <= 0) {
                LOG.error("assignJob()参数非法jobType:{},jobNum:{}", jobType, jobNum);
                throw new BizException(ErrorCode.ILLEGAL_ARGUMENT, "参数非法!");
            }
            LockResultEnum lockResultEnum = null;
            try {
                /** 1、获取业务锁 */
        //这里调用的lockManager.getLock(...)就是之前例子里的
                lockResultEnum = lockManager.getLock(jobType, LockTypeEnum.JOB_LOCK.getCode());
                if (!LockResultEnum.获取锁成功.equals(lockResultEnum)) {//返回emptylist,dispatcher会sleep一定时间,可配置
                    return new ArrayList<JobDO>(0);
                }
    
    
                return doAssignJob(jobType, jobNum);
            } catch (Exception e) {
                LOG.warn("获取锁失败", e);
            } finally {
                lockManager.releaseLock(jobType, LockTypeEnum.JOB_LOCK.getCode(), lockResultEnum);
            }
            return new ArrayList<JobDO>(0);
        }

     

     

     

     

     

    从上可见,这次是要获取数据库锁和行锁都成功才行: if (!LockResultEnum.获取锁成功.equals(lockResultEnum)) {return new ArrayList<JobDO>(0);}

    所以需要在venus_lock表中有对应任务类型的数据,才能使sql:select ID, NAME, REMARK,IS_ENABLED from VENUS_LOCK where NAME = #锁名#and  IS_ENABLED = 'y' FOR UPDATE;执行成功,获取到行锁。

    展开全文
  • 这些锁一般都是自动加锁。不用去管它,只需要知道在什么时候MYSQL会去加锁就行。是否可以手动加锁?可以。事务中的锁 和 非事务中的锁。非事务中的锁,普通锁手动加锁分为:悲观锁和乐观锁。估计是傻B式的加锁(结果...

    锁分为:隐式锁、显式锁。共享锁、排它锁。表锁、行锁、页级锁。

    这些锁一般都是自动加锁。不用去管它,只需要知道在什么时候MYSQL会去加锁就行。

    是否可以手动加锁?

    可以。

    事务中的锁 和 非事务中的锁。

    非事务中的锁,普通锁

    手动加锁分为:悲观锁和乐观锁。估计是傻B式的加锁(结果是:从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作 员中途去煮咖啡的时间,可能忘记解锁)。

    自动加锁:一般MYSQL在执行CREATE,ALTER,INSERT等命令时会自动加锁

    事务中的锁

    事务的四个隔离级别,对应不同的锁机制:

    隔离级别:Read Uncommitted(读取未提交内容)、Read Committed(读取提交内容)、Repeatable Read(可重读)、Serializable(可串行化)

    (Repeatable Read和Serializable)2个事务隔离级别是不需要手动加锁的,我认为在这2个事务级别中加锁是没有意义的,因为其他会话的事务是无法取得这2种事务中执行的数据的。(Repeatable Read和Serializable)获取的永远是原始数据。

    (Read Uncommitted、Read Committed)2个事务隔离级别可以手动加锁,因为这2种级别可能出现(脏读、不可重复读之类的“假数据”),所以在必要的时候进行手动加锁是不错的选择,我暂时是这样理解的。

    解析1:默认事务中从始至终只有一个锁闭合操作,即LOCK TABLES tab;#LOCK#在此中间的 所有SQL语句都不会加锁和解锁,需要手动加锁的话见例1(READ-UNCOMMITTED操作)#UNLOCKUNLOCK TABLES;例1(READ-UNCOMMITTED操作)#会话aSTART TRANSACTION;#开始事务1selectsleep(10)fromfeedbackwhereid<5;#这里会默认加上隐式读锁。 这时我在事务2中 加了写锁,看下是否会等待。(如果不加写锁可能会出现脏读等怪像;也就是说事务2不加写锁的话可以直接进行写操作,出现脏读,那就证明一个事务中 从始至终只有一个锁闭合操作,即解释1的说法)selecttitlefromfeedbackwhereid=1;COMMIT;#提交事务#会话bSTART TRANSACTION;#开始事务2LOCK TABLES feedback WRITE;#加上写锁定, 这时会写锁等待吗?的确被锁住了,我要等待事务1解锁后,我才可以加写锁。以保证事务1能正确地读到我的更新信息,对于并发时候用这个隔离级别的话适合手动加锁来更新消息。update feedbacksettitle='609-1709'whereid=3;#写锁权,执行写操作UNLOCK TABLES;#解除写锁(注意:当当前所有的表均被锁定时,UNLOCK TABLES可以提交事务,我们不想UNLOCK TABLES提交事务,怎么办?)COMMIT;#提交事务

    展开全文
  • 遇到问题: 更新资源sudo apt-get update时遇到 ...E: 无法对目录 /var/lib/apt/lists/ 加锁 解决方法: (1)sudo rm /var/lib/apt/lists/lock (2) ps aux #列出当前进程列表,找到 USER 为 _ap...

    修改了数据源的地址后,用sudo apt-get update 命令升级出现问题。

    遇到问题:

        更新资源`sudo apt-get update`时遇到
        E: 无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用)
        E: 无法对目录 /var/lib/apt/lists/ 加锁
    

    在这里插入图片描述

    解决方法:

    (1)sudo rm /var/lib/apt/lists/lock

    (2)ps aux#列出当前进程列表,找到 USER 为 _apt的,被lock住的进程,记下PID
    (3)再输入sudo kill PID

    解决,舒服~

    Document
    展开全文
  • 代码加锁

    2021-02-03 20:28:32
    加锁前要清楚锁和被保护的对象是不是一个层面的除了没有分析清线程、业务逻辑和锁三者之间的关系随意添加无效的方法锁外,还有一种比较常见的错误是,没有理清楚锁和要保护的对象是否是一个层面的。我们知道静态字段...
  • 文件加锁

    2019-10-07 23:20:27
    文件加锁 可以对同步访问的共享资源文件进行加锁,不过竞争同一个文件的两个线程可能在不同的虚拟机上;或者是一个是Java线程,另一个是操作系统中其他的某个本地线程,文件锁对其他操作系统进程是可见的,因为Java...
  • 易语言程序加锁源码

    2020-07-21 03:16:16
    易语言程序加锁源码,程序加锁,取扩展名,取文件扩展名_
  • 文件夹加锁

    2014-03-29 17:36:01
    一个简单的文件夹加锁程序,配有WPF做的界面,安全性不高仅供学习参考。
  • synchronized 加锁

    2020-06-19 15:28:46
    加锁 :刷新处理器缓存 刷新处理器缓存 处理器通过缓存一致化协议,从除自身外的其他处理器的高速缓存中读取数据,并将结果更新到自己的缓存中 锁的释放:冲刷处理器缓存 冲刷处理器缓存 将对变量的修改结果写入...
  • 参考:MySQL 加锁处理分析。该文已经讲的很详尽了,也易懂,下面仅仅是个人做的总结。一、 背景1.1 隔离级别1.2 加锁过程逐条处理,逐条加锁。1.3 两阶段锁2PL1.4 gap锁gap锁是间隙锁,即相邻两条有效记录间隙的锁...
  • synchronized加锁

    2020-01-19 09:11:51
    对于想锁住静态变量,加锁是加在类上(XX.class)
  • php并发加锁示例

    2020-10-21 07:50:41
    本文介绍了php并发加锁示例,对数据进行加锁,只容许一个用户在一个时间内进行操作,这个时候就需要用到锁了,需要的朋友可以了解一下。
  • RedisTemplate加锁

    2020-11-05 14:32:13
    @Autowired ... * 加锁(自动重试) * * @param key * @param lockKeyType * @return */ public boolean tryLock(String key, String lockKeyType) { boolean flag = false; try { key...
  • 订单加锁

    2019-12-17 17:34:19
    订单加锁第一种方式使用数字据增加版本字段的方式针对卖商品比较合适第二种方式使用redis加锁的方式针对竞争性操作合适第三种方式 redis watch 第一种方式使用数字据增加版本字段的方式针对卖商品比较合适 基本思路...
  • 域名加锁

    2019-10-08 20:20:49
    域名锁定能将您的域名加锁,使其在加锁期间不接受用户的任何更改,为您的解析保驾护航! 2、什么情况下用到域名锁定功能? 域名锁定功能,就是为了防止一些由于帐号密码泄漏、或者域名注册信息被黑导致域名被...
  • Java加锁工具类

    2019-05-24 09:06:15
    Java加锁工具类。用于普通加锁。 可以用到的场景有: 1、多线程对同一数据进行处理时,通过此类进行简单加锁。 2、想保证后台同时,只有一个线程在处理某事情时。 3、更新数据库信息时。
  • 网站加锁失效

    2020-11-27 19:32:46
    <div><p>不知是否我设置的原因,网站加锁按照教程加锁无效。</p><p>该提问来源于开源项目:You2php/delete</p></div>
  • 客户端加锁

    2019-02-02 14:34:07
    客户端加锁是指,对于使用某个对象X的客户端代码,使用X本身用于保护其状态的锁来保护这段客户端代码。要使用客户端加锁,必须知道对象X使用的是哪一种锁。 public class ListHelper&lt;E&gt; { public ...
  • JAVA Lock加锁实例

    2018-07-10 16:11:17
    Lock锁是对象锁,仅在同一对象中,锁才会生效。...lock.tryLock()的加锁方式,不会堵塞,会立即返回加锁成功与否。(方案AEX) lock.tryLock(1000, TimeUnit.SECONDS)的加锁方式,允许堵塞时间,若在堵……
  • QT加锁

    千次阅读 2019-03-25 17:15:42
    #include <iostream> #include <thread>...//加锁 using namespace std; volatile int counter(0);//在内存中直接取得 mutex mtx; void increase10Ktimes() { for(int i=0...
  • 在对文件操作过程中,有时候需要对文件进行加锁操作,防止其他线程访问该文件。对文件的加锁方法有两种:第一种方法:使用RandomAccessFile类操作文件。在java.io.RandomAccessFile类的open方法,提供了参数实现独占...
  • 之前的一篇文章介绍了mysql的四种隔离级别,本篇主要介绍一下mysql是如何进行加锁处理的。主要想了解mysql在处理高并发情况下的读写以及可能遇到的并发问题之间是如何去兼容的。我们都知道加锁是比较资源的操作,...
  • linux加锁

    2016-04-24 11:11:50
    加锁1. 为什么要加锁加锁是为了防止死锁。死锁: 是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或...
  • 一、背景MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题。本文,准备就MySQL/InnoDB...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,879
精华内容 13,951
关键字:

加锁