package com.pjf.common.scheduler;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import com.pjf.common.log.LoggerUtil;
/**
* 多线程数据定时循环处理器<BR>
* 可以通过参数的调整,调整适宜的线程数处理数据
*/
public class MultiThreadLoopWorker<K, V> implements IControl {
private final String name;
private final int divideMapNum;
private final int threadNum;
private final long threadInterval;
private final long processPerformance;
private final IProcessor<K, V> processor;
private volatile boolean running;
private final ArrayList<ConcurrentHashMap<K, V>> mapList;// 自维护队列
private final Thread[] threads;
public MultiThreadLoopWorker(String name, int divideMapNum, int threadNum, long threadInterval,
long processPerformance, IProcessor<K, V> processor) {
this.name = name;
this.divideMapNum = divideMapNum;
this.threadNum = Math.min(threadNum, divideMapNum);
this.threadInterval = threadInterval;
this.processPerformance = processPerformance;
running = false;
this.processor = processor;
mapList = new ArrayList<ConcurrentHashMap<K, V>>(divideMapNum);
for (int i = 0; i < divideMapNum; i++) {
mapList.add(new ConcurrentHashMap<K, V>());
}
threads = new Thread[threadNum];
for (int i = 0; i < threads.length; i++) {
String threadName = String.format("%s-Pool%d-%d", name, threadNum, i);
threads[i] = new Thread(new MyRunnable(i), threadName);
threads[i].setDaemon(true);
}
}
/**
* 只能开启一次,关闭后再开会抛异常
*/
@Override
public synchronized void start() {
if (!running) {
running = true;
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
LoggerUtil.infof("<MultiThreadLoopWorker> worker[%s] started, %d thread(s)", name, threads.length);
}
}
@Override
public synchronized void shutdown() {
if (running) {
running = false;
LoggerUtil.infof("<MultiThreadLoopWorker> shutting down worker[%s]", name);
for (int i = 0; i < threads.length; i++) {
threads[i].interrupt();
}
}
}
@Override
public boolean isRunning() {
return running;
}
public V putIfAbsent(K key, V value) {
int index = Math.abs(key.hashCode()) % divideMapNum;
ConcurrentHashMap<K, V> map = mapList.get(index);
return map.putIfAbsent(key, value);
}
public V put(K key, V value) {
int index = Math.abs(key.hashCode()) % divideMapNum;
ConcurrentHashMap<K, V> map = mapList.get(index);
return map.put(key, value);
}
public V get(K key) {
int index = Math.abs(key.hashCode()) % divideMapNum;
ConcurrentHashMap<K, V> map = mapList.get(index);
return map.get(key);
}
public V remove(K key) {
int index = Math.abs(key.hashCode()) % divideMapNum;
ConcurrentHashMap<K, V> map = mapList.get(index);
return map.remove(key);
}
private class MyRunnable implements Runnable {
private final ArrayList<ConcurrentHashMap<K, V>> list = new ArrayList<ConcurrentHashMap<K, V>>();
private MyRunnable(int index) {
for (int i = index; i < mapList.size(); i += threadNum) {
list.add(mapList.get(i));
}
}
public void run() {
while (running) {
long startTime = System.currentTimeMillis();
int entryCount = 0;
for (int i = 0; i < list.size() && running; i++) {
ConcurrentHashMap<K, V> map = list.get(i);
entryCount += map.size();
for (Iterator<Entry<K, V>> it = map.entrySet().iterator(); it.hasNext() && running;) {
Entry<K, V> entry = it.next();
try {
K key = entry.getKey();
V value = entry.getValue();
if (value == null || processor.process(key, value)) {
it.remove();
}
} catch (Throwable t) {
if (running) {
LoggerUtil.errorf("<MultiThreadLoopWorker> LoopWorker[%s] process error.", t, name);
}
}
}
}
long costTime = System.currentTimeMillis() - startTime;
if (costTime > processPerformance) {
LoggerUtil.warnf("<MultiThreadLoopWorker> LoopWorker[%s] use time:%dms entry count:%d", name,
costTime, entryCount);
}
try {
Thread.sleep(threadInterval);
} catch (InterruptedException e) {
// 这里报错不用记日志
e.printStackTrace();
}
}
}
}
public interface IProcessor<K, V> {
/**
* @return true:将从处理队列中移除key对应数据
*/
public boolean process(K key, V value);
}
}