Jive中自动索引机制研究 ---定时器模式的使用

      作者:李新春    email:xinchunli1982@163.com  

 

   搜索之前先要用lucene进行索引,这是lucene的工作原理。后台建立索引的工作是一个线程程序运行。在jive中是一个定时任务。其整体的设计思路和jdk中的Timer 类的设计思路有点相似。

首先回忆一下Timer的使用。

有三个步骤:

1,定义一个类继承TimerTask

2, 实例化一个Timer

3,利用Timer启动一个定时任务。

举例:

                            Public class SayHello extends TimerTask

                            {

                                   Public void run(){}

                            }

                            Timer tasktimer = new Timer();

                            TimerTask timertask = new SayHello();

                            tasktimer. scheduleAtFixedRate(timertask,delay,period);

 

jive中其实最终也是这样操作的,但是它在上面包装了几层,看起来好像有些晦涩,难以理解,下面我就层层剥开,透彻领悟一下大侠的设计思想。

最终的操作如下:

TaskEngine

public static TimerTask scheduleTask(Runnable task, long delay,long period)

     {

        TimerTask timerTask = new ScheduledTask(task);

        taskTimer.scheduleAtFixedRate(timerTask, delay, period);

        return timerTask;

    }

不管返回值如何,其中调用也是用了三步,taskTimerTimer类型的。在函数外面实例化:

taskTimer = new com.jivesoftware.util.Timer(true);TimerTask实例化,然后调用scheduleAtFixedRate 方法。但是为什么这么设计呢?按照自己的设计思路,应该做如下操作:

public class DbSearchManager implements Runnable{

       public void run()

       {

              if (!searchEnabled) {      //预留接口

            return;

        }

              addTask(new IndexTask());

       }

      

       private void addTask (TimerTask task) {

              Timer timer = new Timer();

              timer.scheduleAtFixedRate(task, 1000, 1000);

       }

 

       class IndexTask extends TimerTask

       {

              public void run()

              {

                     System.out.println("Indexing....");

              }

       }

}

线程类IndexTask负责建立索引,线程类DbSearchManager负责启动索引线程。

学习点: 如何在取消这个定时任务呢。当然在DbSearchManager中可以做到。

增加一个变量 private TimerTask task = null; 然后增加一个方法

public void cancel()

       {

              if(task == null)

                     return;

              task.cancel();

       }

}

addTask(new IndexTask());改为: task = new IndexTask() ; addTask(task); 欧了。

 

上面代码的缺点:这里只有一个IndexTask任务,代码量看起来不是很大,如果这里的任务有10个,100个,还要这么写吗?每个任务都要addTask(),然后顺序的执行么?有没有办法把这些任务执行管理起来?答案是肯定的。我只把这些任务生成出来,交给这个管理类去处理就ok了,至于怎么执行,是单线程,还是多线程执行是他的任务了。降低了代码的耦合度。

       好了,有了上面的思想就前进了一大步,继续我们的设计。下面设计一个任务管理类,这个类必须能接纳和执行我们的任务。

public class TaskEngine {

 

       //保存,接纳过来的任务

       private static ArrayList<TimerTask> tasks = new ArrayList<TimerTask>();

 

       private static Object lock = new Object();

       private static Timer taskTimer ;

       static

       {

              taskTimer = new Timer();

              TaskEngineWorker worker = new TaskEngineWorker();

              Thread thread = new Thread(worker);

              thread.start();

       }

       public static void addTask(TimerTask task)

       {

              tasks.add(task);

       }

       public static void deleteTask(TimerTask task)

       {

              if(tasks.contains(task))

              {

                     tasks.remove(task);

              }

       }

       public static void scheduleTask(TimerTask task,  long delay, long period)

    {

        taskTimer.scheduleAtFixedRate(task, delay, period);

    }

       public static TimerTask nextTask()

       {    

              synchronized(lock) {

            // Block until we have another object in the queue to execute.

            while (tasks.isEmpty()) {

                try {

                    lock.wait();

                }

                catch (InterruptedException ie) { }

            }

            return tasks.remove(tasks.size()-1);

        }

             

       }

      

   private static class TaskEngineWorker implements Runnable {     

        public void run() {

            while (true) {

                nextTask().run();

            }

        }

    }

}

 

 

 

上面的程序就和jive中的有点像了,但是有以下几点不同:

1,  这里我们开辟了一个TaskEngineWorker线程,jive中开辟了7个线程来执行任务。效率明显要高。

2,  我们用ArrayList来保存接收到的任务,jive中用LinkedList来接收

3,  我们加入的任务都是TimerTask的,不具有普遍性,对于一般的线程任务也要接收,jive中用一个类ScheduledTask进行转化。

根据以上几点,我们再次改进相关类。

最后,有点不同的是DbSearchManager类的构造函数中

timerTask = TaskEngine.scheduleTask(

                    this,autoIndexInterval*JiveGlobals.MINUTE,

                    autoIndexInterval*JiveGlobals.MINUTE);

 

把自己this 添加到任务中去。呵呵,知道为什么作者这么设计吗?刚才上面提到了,TaskEngine是一个线程执行的模式,既然DbSearchManager也是一个线程,那么他的定时执行任务,我们也把他加到TaskEngine中去吧,如何执行交给TaskEngine来处理,模式的功能真的很强大。用这些模式来改变自己的设计理念,如果DbSearchManager自己处理,就增加了代码的维护量,提高了代码的耦合度。 

 


好了,到这里就完整的讲解了定时索引的所有结构和代码,从中可以体会作者的代码精妙之处。至于LinkedList ArrayList 的性能比较,另篇处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值