java web项目在双机下的定时任务

问题:一个项目,部署在多台服务器上,里面有一个定时任务需要执行,会重复执行多次。
解决方法:
方案一:项目中配置一个运行定时任务的主机名,然后在启动定时任务的方法内部,获取当前运行的服务器的主机名,与配置的主机名是否一致,假如一致,则任务继续往下执行;不一致,直接return。
具体代码:
1、linux系统下,执行hostname命令,得到如下结果:localhost.localdomain,其中localhost表示主机名,localdomain为域名,具体参考:linux下怎么查看主机名以及修改主机名
2、java代码:

            //系统配置的主机名,多个,以逗号分割
String host = "localhostName";
host = host.replaceAll(" ", "");
String[] hosts = host.split(",");
java.net.InetAddress ia = null;
try {
            ia = ia.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return;
        }
        //获取当前服务器的主机名
        String hostName = ia.getHostName();
        boolean flag = false;
        for (String str : hosts) {
            if (hostName.equals(str.replaceAll(" ", ""))) {
                flag = true;
            }
        }
        // 判断本地主机名称是否与系统配置的同步主机名称一致,不一致则返回
        if (!flag) {
            return;
        }

方案二:
在数据库中,增加一个字段tasktime,来存放运行当前执行的定时任务的时间和一个随机数,关键代码:

SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhh");
String timeStr = format.format(new Date());
String random = UUID.randomUUID().toString()
//将当前时间的年月日时+随机数拼接,存放在tasktime字段里面,如2017022823xxxxx。
String tasktime= timeStr + "_" + random;
/**
 * 编写修改该字段值的sql语句,语句的含义是:假如数据库tb_task中,tasktime中包含的年月日时,
 * 和当前系统的年月日时不相等,则进行更新。说明:当tasktime中的时间和当前系统中的年月日时相等,
 * 就说明该定时任务已经执行了,或者正在执行,这样其他服务器运行到这里时就不会走这条更新语句,
 * 那么下面的查询中,也不会查询到tasktime和当前服务器产生的tasktime相等的记录,其他服务器也不
 * 会往下运行该定时任务了。
 */
String update_sql = "UPDATE tb_task SET tasktime=\"" + tasktime
+ "\" tasktime NOT LIKE '"
+ timeStr + "_%'";
//执行sql
executeSql(update_sql);

//查询刚刚修改的那个字段值是否存在
String query_sql = "select  count(*) from tb_tasktime where tasktime="+tasktime;
//执行sql
int count = executeSql(query_sql);
if (0==count)
    return;//没有查询到结果,则不往下执行定时任务:数据库中保存的tasktime值和该服务器产生的不一致。
//运行定时任务的具体内容...

以上方案都存在缺陷,方案一,假如配置的那台执行定时任务的服务器宕机了,则定时任务也不会执行了。
方案二,假如定时任务要精确到分或者秒,而且执行该定时任务的时间超过了tasktime中设置的分或者秒,那么就会丢失掉一部分定时任务执行的次数,不过在定时任务的整个方法上加同步锁synchronized,可以解决方案二的缺陷。

你可能感兴趣的:(java后台开发)