java 防并发,集群环境下防止并发的一种实现

?

近来研究定时器Quartz集群的实现原理时,发现了一种利用数据库锁的方式来实现集群环境下进行并发控制的方式。由于现在的系统多是部署在集群环境中,需要进行并发控制时,这是一种很好的实现方法,现将原理介绍如下:

?

首先,在数据库中建立一张拥有锁标识的表,建立表的SQL语句如下:

? ? ? ??CREATE TABLE TB_LOCKS

(LOCK_NAME VARCHAR2(40) NOT NULL,

PRIMARY KEY (LOCK_NAME)

)

? ? ? ??表创建好之后,插入一些数据,?这些数据是根据数据库的业务逻辑操作抽象出的系统所拥有的表的类型,如"TRIGGER_ACCESS"就表示对任务触发器相关的信息进行修改caozuo.html" target="_blank">删除操作时所需要获得的锁。每当要进行与某种业务相关的数据库操作时,先去这张表中查询操作相关的业务对象所需要的锁,如Quartz中需要修改触发气的状态,下次触发时间时,就需要获得"TRIGGER_ACCESS"所表示的锁。这时,执行查询这个表数据的SQL形如“select * from TB_LOCKS t where t.lock_name='TRIGGER_ACCESS' for update”,在select之后加了“for update”,就如JAVA语言中的为方法加上Symchriozed一样,起到了串形化访问修改所需数据的作用。当一个线程使用上述的SQL对表中的数据执行查询操作时,若查询结果中包含相关的行,数据库就会对这些行进行ROW LOCK。若此时又有另外一个线程使用相同的SQL对表的数据进行查询时,由于查询出的数据行已经被数据库锁住了,此时这个线程就只能等待,直到拥有这些行锁的线程完成了相关的业务操作,执行了commit动作后,数据库才会释放了相关行的锁,这个线程才能继续执行。通过这样的机制,在集群环境下,结合乐观锁的机制就可以防止一个线程对数据库数据的操作的结果被另外一个线程所覆盖,从而可以避免一些难以觉察的错误发生。当然,达到这种效果的前提是需要把Connection设置为手动提交,即autoCommit为false,下面是执行相关步骤的程序代码:

?

/**

* Execute the given callback having optionally aquired the given lock.

* This uses the non-managed transaction connection.

*

* @param lockName The name of the lock to aquire, for example

* "TRIGGER_ACCESS". If null, then no lock is aquired, but the

* lockCallback is still executed in a non-managed transaction.

*/

protected Object executeInNonManagedTXLock(

String lockName,

TransactionCallback txCallback) throws JobPersistenceException {

boolean transOwner = false;

Connection conn = null;

try {

if (lockName != null) {

if (getLockHandler().requiresConnection()) {

conn = getNonManagedTXConnection();

}

//获得相关的锁,通过带有"for update"的select语句实现,如果这个锁被其他线程占用,执行这个操作的线程只能等待

transOwner = getLockHandler().obtainLock(conn, lockName);

}

if (conn == null) {

conn = getNonManagedTXConnection();

}

Object result = txCallback.execute(conn);//执行相关的业务逻辑操作,获得操作的结果

commitConnection(conn);//提交操作结果,释放锁

return result;

} catch (JobPersistenceException e) {

rollbackConnection(conn);//撤销操作结果,释放锁

throw e;

} catch (RuntimeException e) {

rollbackConnection(conn);//撤销操作结果,释放锁

throw new JobPersistenceException("Unexpected runtime exception: "

+ e.getMessage(), e);

} finally {

try {

releaseLock(conn, lockName, transOwner);

} finally {

cleanupConnection(conn);

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 答:Java实现定时任务的方式有三种:1.使用java.util.Timer类;2.使用java.util.concurrent.ScheduledThreadPoolExecutor类;3.使用Quartz框架。 ### 回答2: Java实现定时任务有以下几种方式: 1. Timer类:Java提供了Timer类来帮助实现定时任务。通过创建一个Timer实例和一个TimerTask实例,可以设定任务的执行时间和间隔时间,然后使用Timer的schedule()方法来启动任务。 2. ScheduledExecutorService接口:Java提供了ScheduledExecutorService接口来实现定时任务。该接口继承自ExecutorService接口,可以使用ThreadPoolExecutor来实现。通过调用schedule()方法,可以设定任务的执行时间和间隔时间,然后将任务提交给ScheduledExecutorService。 3. cron表达式:在Java中,还可以使用cron表达式来实现定时任务。cron表达式是一种用来设置时间的字符串格式,通过设置不同的字段,可以实现精确到秒的定时任务。可以使用Quartz框架等工具来解析和执行cron表达式。 4. Spring框架的@Scheduled注解:如果在Spring框架中开发应用,可以使用@Scheduled注解来实现定时任务。通过在方法上标记@Scheduled注解,并设置相应的时间表达式,可以让方法在指定的时间间隔内执行。 需要注意的是,以上方式都是基于Java的定时任务实现,可以根据具体需求选择最合适的方式来实现定时任务。 ### 回答3: 在Java中,我们可以使用以下几种方式来实现定时任务。 1. Timer类:Java中的Timer类是一个简单的定时器工具,它可以通过创建Timer对象并调用其schedule()方法来设置定时任务。该方法可以指定一个任务(实现了TimerTask接口的类)和一个延迟时间,然后在延迟时间之后开始执行定时任务。 2. ScheduledExecutorService接口:Java中的ScheduledExecutorService接口是一个在指定的延迟时间之后或者以固定的时间间隔重复执行任务的调度器。可以使用Executors工厂类的newScheduledThreadPool()方法创建ScheduledExecutorService对象,并使用其schedule()方法来设置定时任务。 3. Quartz框架:Quartz是一个功能强大且灵活的开源定时任务调度框架。它提供了许多高级的调度功能,如任务的并发执行、动态调度、集群支持等。使用Quartz框架,我们可以通过配置定时任务的详细信息(如触发器、调度器等),然后让框架来管理和执行定时任务。 4. Spring的Task:Spring框架提供了一个简单的任务调度器,可以通过配置的方式实现定时任务。在Spring的配置文件中,我们可以使用<task:scheduler>和<task:scheduled>标签来定义定时任务的调度器和具体的定时任务方法。 综上所述,Java实现定时任务的方式有多种选择。根据需求的复杂性和灵活性的要求,我们可以选择适合的方式来实现定时任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值