定时器机制及锁实现

本文探讨了在分布式系统中如何实现定时器任务,并强调了使用分布式锁的重要性,以防止资源浪费和业务失败。详细介绍了定时器的三个步骤设置,以及依赖数据库的锁实现方法。同时,指出了在实现过程中应注意的事项,包括正确释放锁和时钟同步问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

应用场景

在需要定时执行任务时就需要代码实现定时器任务,但是现在的系统大多是分布式系统,N台业务逻辑服务器同一时刻执行任务,如果不作处理,务必会造成资源的严重浪费,严重情况还会引起业务的失败。所以此时就需要实现分布式锁来保证同一时刻只有一台服务器执行该任务,不仅节约了系统资源,在保证高可用的情况下,还能正常的保证业务逻辑的实现。

代码实现

定时器

第一步

设置需要实现定时任务的bean与需要执行的方法名

    <bean id="jobDetail1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="Scheduler1">
        </property>
        <property name="targetMethod" value="run"/>
        <!-- 是否允许任务并发执行。当值为false时,表示必须等到前一个线程处理完毕后才再启一个新的线程 -->
        <property name="concurrent" value="false"/>
    </bean>
第二步

执行该定时任务的频率,cron表达式工具详见:http://cron.qqe2.com/

    <bean id="Triggers1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="jobDetail1">
        </property>
        <property name="cronExpression">
            <!--Cron表达式的格式:秒 分 时 日 月 周 年(可选), 30s一次-->
            <value>*/30 * * * * ?</value>
        </property>
    </bean>
第三步

将设置好的触发器纳管

    <bean id="Scheduler1" autowire="no"  class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="Triggers1"></ref>
            </list>
        </property>
        <property name="autoStartup" value="true"></property>
    </bean>

锁实现

锁实现依赖于数据库,表结构与代码参考如下:
表结构

逻辑代码
LockUtils代码如下:

package test.util;

import java.util.Date;

/**
 * 该类提供抢锁、释放锁操作<br/>
 * 保证N台服务器同一时刻只会有一台服务器执行某一操作<br/>
 *
 * @author 
 */
public class LockUtils {

    private static final String UNLOCK = "UNLOCK";
    private static final String LOCK = "LOCK";

    /**
     * 抢锁
     *
     * @param transCoreLockDao
     * @param lockKey
     * @return
     */
    public static boolean getLock(TransCoreLockDao transCoreLockDao, String lockKey) {
        TransCoreLock transCoreLock = getTransCoreLock(lockKey, UNLOCK);
        return transCoreLockDao.updateByEntity(SQL.get(SQL.UPDATE_TRANS_LOCK_TO_GET_LOCK), transCoreLock) > 0;
    }

    /**
     * 释放锁
     *
     * @param transCoreLockDao
     * @param lockKey
     * @return
     */
    public static boolean releaseLock(TransCoreLockDao transCoreLockDao, String lockKey) {
        TransCoreLock transCoreLock = getTransCoreLock(lockKey, LOCK);
        return transCoreLockDao.updateByEntity(SQL.get(SQL.UPDATE_TRANS_LOCK_TO_RELEASE_LOCK), transCoreLock) > 0;
    }

    /**
     * 通过key和lock标识生成对象
     *
     * @param lockKey
     * @param lock
     * @return
     */
    private static TransCoreLock getTransCoreLock(String lockKey, String lock) {
        TransCoreLock transCoreLock = new TransCoreLock();
        transCoreLock.setLockKey(lockKey);
        transCoreLock.setLockFlag(lock);
        transCoreLock.setUpdateDt(new Date());
        return transCoreLock;
    }
}

注意事项:

1.代码层面一定要极其注重还锁,否则容易影响下一次乃至以后所有的抢锁操作(正常逻辑及异常逻辑的还锁操作)
2.定时器锁较依赖于时钟同步,如果出现时间不同步,则可能会出现,同时两台或N台服务器执行业务逻辑,原因是某台服务器抢到锁–>执行业务逻辑成功→还锁等一系列操作均已完成,也许只是用了几十毫秒时间,另外一台由于时间的未同步,又继续执行了业务逻辑
3.该实现方式建议不作为影响交易逻辑等重要环节的解决方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值