ribbon中,发现一段比较有水平的代码.md
ribbon中,发现一段比较有水平的代码
简介
有个类,com.netflix.loadbalancer.PollingServerListUpdater,主要功能是,获取服务的instance列表。
这也是ribbon中的核心代码。
public class PollingServerListUpdater implements ServerListUpdater {
该接口的功能,给大家看下:
public interface ServerListUpdater {
/**
* 1 an interface for the updateAction that actually executes a server list update
*/
public interface UpdateAction {
void doUpdate();
}
/**
* start the serverList updater with the given update action
* This call should be idempotent.
*
* @param updateAction
*/
void start(UpdateAction updateAction);
/**
* stop the serverList updater. This call should be idempotent
*/
void stop();
/**
* @return the last update timestamp as a {@link java.util.Date} string
*/
String getLastUpdate();
/**
* @return the number of ms that has elapsed since last update
*/
long getDurationSinceLastUpdateMs();
/**
* @return the number of update cycles missed, if valid
*/
int getNumberMissedCycles();
/**
* @return the number of threads used, if vaid
*/
int getCoreThreads();
}
其实这个接口的几个方法,主要就是,维护了一个线程池,然后定期去调用1处的UpdateAction,获取最新的服务列表,比如调用eureka client的方法,去eureka server获取服务列表。
静态类单例模式
下面这个方法,获取线程池,里面用了一个静态内部类:
private static ScheduledThreadPoolExecutor getRefreshExecutor() {
return LazyHolder._serverListRefreshExecutor;
}
com.netflix.loadbalancer.PollingServerListUpdater.LazyHolder
private static class LazyHolder {
private final static String CORE_THREAD = "DynamicServerListLoadBalancer.ThreadPoolSize";
private final static DynamicIntProperty poolSizeProp = new DynamicIntProperty(CORE_THREAD, 2);
private static Thread _shutdownThread;
static ScheduledThreadPoolExecutor _serverListRefreshExecutor = null;
static {
// 1
int coreSize = poolSizeProp.get();
ThreadFactory factory = (new ThreadFactoryBuilder())
.setNameFormat("PollingServerListUpdater-%d")
.setDaemon(true)
.build();
// 2
_serverListRefreshExecutor = new ScheduledThreadPoolExecutor(coreSize, factory);
// 3
poolSizeProp.addCallback(new Runnable() {
@Override
public void run() {
// 4
_serverListRefreshExecutor.setCorePoolSize(poolSizeProp.get());
}
});
// 5
_shutdownThread = new Thread(new Runnable() {
public void run() {
logger.info("Shutting down the Executor Pool for PollingServerListUpdater");
shutdownExecutorPool();
}
});
Runtime.getRuntime().addShutdownHook(_shutdownThread);
}
private static void shutdownExecutorPool() {
if (_serverListRefreshExecutor != null) {
_serverListRefreshExecutor.shutdown();
if (_shutdownThread != null) {
try {
Runtime.getRuntime().removeShutdownHook(_shutdownThread);
} catch (IllegalStateException ise) { // NOPMD
// this can happen if we're in the middle of a real
// shutdown,
// and that's 'ok'
}
}
}
}
}
-
1处,获取要构造的线程池的core线程的数量
-
2处,new了一个线程池,使用的就是jdk里面的java.util.concurrent.ScheduledThreadPoolExecutor
-
3处,这里的poolSizeProp,可以通过Archaius来进行修改,这个Archaius听说挺强的,但是没用过,可以理解为一个配置中心吧,可以通过Archaius修改线程池的线程数量,这里加了个回调,意思是,如果线程池数量变更了,调用这个回调方法
-
4处,这里直接调用了ScheduledThreadPoolExecutor的setCorePoolSize方法,大家可以看看下面的代码:
java.util.concurrent.ThreadPoolExecutor#setCorePoolSize public void setCorePoolSize(int corePoolSize) { if (corePoolSize < 0) throw new IllegalArgumentException(); int delta = corePoolSize - this.corePoolSize; // 4.1 this.corePoolSize = corePoolSize; if (workerCountOf(ctl.get()) > corePoolSize) interruptIdleWorkers(); else if (delta > 0) { // We don't really know how many new threads are "needed". // As a heuristic, prestart enough new workers (up to new // core size) to handle the current number of tasks in // queue, but stop if queue becomes empty while doing so. int k = Math.min(delta, workQueue.size()); while (k-- > 0 && addWorker(null, true)) { if (workQueue.isEmpty()) break; } } }
看看,4.1,这里对field:corePoolSize进行了修改。
private volatile int corePoolSize;
那,大家明白为啥要定义成volatile了吗?
-
5处,添加一个ShutdownHook,进程关闭时(kill 9不行,要kill 15),会回调该ShutdownHook,关闭线程池。
线程池开始获取服务列表
private final AtomicBoolean isActive = new AtomicBoolean(false);
// 1
private volatile long lastUpdated = System.currentTimeMillis();
private final long initialDelayMs;
private final long refreshIntervalMs;
private volatile ScheduledFuture<?> scheduledFuture;
@Override
public synchronized void start(final UpdateAction updateAction) {
// 2
if (isActive.compareAndSet(false, true)) {
final Runnable wrapperRunnable = new Runnable() {
@Override
public void run() {
// 3
if (!isActive.get()) {
if (scheduledFuture != null) {
// 4
scheduledFuture.cancel(true);
}
return;
}
try {
// 5
updateAction.doUpdate();
lastUpdated = System.currentTimeMillis();
} catch (Exception e) {
logger.warn("Failed one update cycle", e);
}
}
};
// 6
scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
wrapperRunnable,
initialDelayMs,
refreshIntervalMs,
TimeUnit.MILLISECONDS
);
} else {
logger.info("Already active, no-op");
}
}
- 1处,需要跨线程访问的,该加volatile就加
- 2处,使用原子类,避免多次被执行
- 3处,使用原子boolean作为开关,方便线程及时停止运行
- 4处,停止运行时,不忘记关闭定时任务,秀。
- 5处,可以算作是策略或者模板方法模式吧
- 6处,新建线程池,重点是保存返回的future
线程池如何停止
@Override
public synchronized void stop() {
if (isActive.compareAndSet(true, false)) {
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
}
} else {
logger.info("Not active, no-op");
}
}
其他几个方法实现
@Override
public String getLastUpdate() {
return new Date(lastUpdated).toString();
}
@Override
public long getDurationSinceLastUpdateMs() {
return System.currentTimeMillis() - lastUpdated;
}
@Override
public int getNumberMissedCycles() {
if (!isActive.get()) {
return 0;
}
return (int) ((int) (System.currentTimeMillis() - lastUpdated) / refreshIntervalMs);
}
@Override
public int getCoreThreads() {
if (isActive.get()) {
if (getRefreshExecutor() != null) {
return getRefreshExecutor().getCorePoolSize();
}
}
return 0;
}
private static long getRefreshIntervalMs(IClientConfig clientConfig) {
return clientConfig.get(CommonClientConfigKey.ServerListRefreshInterval, LISTOFSERVERS_CACHE_REPEAT_INTERVAL);
}