不要使用轮询

公司产品要集成LDAP,可以支持5个LDAP服务器,我们要写代码定期和LDAP服务器的信息进行同步,但是每个LDAP服务器的同步周期是变化的,用户可以配置。最简单的方式就是每个LDAP起一个线程做这个工作,但是架构师不允许太多的线程,所以要用一个主线程来控制。本来负责这个功能的人要使用轮询的方式,因为他觉得用户什么时候修改那个周期是不确定的,所以要一直查。其实很简单,如果其它的地方修改了那个周期,它通知那个主线程哪个服务器的周期修改了就行,然后主线程中断休眠并重新计算应该休眠的时间。主线程大部分时间都处于休眠状态,每次都会重新计算下一次应该休眠多长时间,这样程序的性能就大大的提高了。

演示代码如下:
import java.util.ArrayList;
import java.util.List;

public class MainThread extends Thread {
    private List servers;

    private static MainThread instance;

    public static void updatePeriod(String serverName, long period) {
        for (int i = 0; i < instance.servers.size(); i++) {
            Object[] server = (Object[]) instance.servers.get(i);
            if (server[0].equals(serverName)) {
                server[2] = new Long(period);
                break;
            }
        }
        instance.interrupt();

    }

    public MainThread() {
        instance = this;
        servers = new ArrayList();
        Object[] server1 = new Object[3];
        server1[0] = "server1";
        server1[1] = new Long(System.currentTimeMillis());
        server1[2] = new Long(2000);
        servers.add(server1);
        Object[] server2 = new Object[3];
        server2[0] = "server2";
        server2[1] = new Long(System.currentTimeMillis());
        server2[2] = new Long(3000);
        servers.add(server2);
    }

    public void run() {
        while (true) {
            try {
                long current = System.currentTimeMillis();
                long sleepTime = Long.MAX_VALUE;
                for (int i = 0; i < servers.size(); i++) {
                    Object[] server = (Object[]) servers.get(i);
                    long last = ((Long) server[1]).longValue();
                    long period = ((Long) server[2]).longValue();
                    long next = last + period;
                    long sleep = next - current;
                    if (sleepTime > sleep) {
                        sleepTime = sleep;
                    }
                    if (sleep <= 0) {
                        System.out.println("Synch thread started.");
                        server[1] = new Long(current);
                    }
                }
                if (sleepTime > 0) {
                    Thread.sleep(sleepTime);
                }
            } catch (InterruptedException e) {
                System.out.println("Interrupted.");
            } catch (Throwable t) {
               
            }
        }
    }

    public static void main(String[] args) {
        MainThread thread = new MainThread();
        thread.start();
        try {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(2000);
                updatePeriod("server1", 3000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

要强调一点的是,几乎所有的轮询都可以使用类似都方式解决,轮询做太多的无用功。另外一种好的方式就是使用Observer模式,和这个的性能类似。


作者: Cherami
原载: 不要使用轮询
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。

日志评价

 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 Votes | Average: 0 out of 5 (暂无评价) --点击星星直接投票
Loading ... Loading ...


相关日志

  • 暂时没有相关日志。


随机日志



添加到网摘

[del.icio.us]  [新浪 VIVI]  [365key]  [YouNote]  [博采中心]  [Poco]  [SOHU狐摘]  [天极网摘]  [和讯网摘]
喜欢这个插件?

当前日志信息