我对线程池有点困惑,并从for循环中提供退出条件。关于如何正确地做到这一点,我还没有找到合适的解释。我一直在尝试一些可能性,但我被困住了
我有这段代码。
@Override
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void auditAllDomainConfigurationStatuses() {
logger.info("Starting audit of all domain configuration statusses");
int errorStatusCounter = 0;
Map<SubdomainRegistryStatus, List<String>> domainsByStatus = new HashMap<SubdomainRegistryStatus, List<String>>();
List<DomainConfigurationStatus> domains = domainConfigurationStatusDao.findAll();
for (DomainConfigurationStatus domainConfigurationStatus : domains) {
String domainName = domainConfigurationStatus.getDomainName();
DomainConfigurationStatus result = domainConfigurationStatusAuditor.auditDomainConfigurationStatus(domainConfigurationStatus.getId());
addDomainToDomainsByStatusMap(domainsByStatus, result, domainName);
if(SubdomainRegistryStatus.ERROR.equals(result.getStatus())){
errorStatusCounter++;
if(errorStatusCounter >= EMERGENCY_AUDIT_STOP_LIMIT){
logger.error("Emergency audit stop more then " + EMERGENCY_AUDIT_STOP_LIMIT + " records went into status ERROR");
mailEmergencyDomainConfigurationStatusAuditStop();
return;
}
}else{
errorStatusCounter = 0;
}
}
mailDomainConfigurationStatusReport(domainsByStatus);
logger.info("Audit of all domain configuration statusses completed");
}
此代码将在某处调用域的dns来获取它的ip。然后它将更新数据库中的状态。相当简单的事情。但是,如果X之后的状态转换为ERROR,那么企业希望我们停止整个过程。我设法写了这个,用上面的方法很简单。然而,调用dns来获取ip的速度很慢,我每秒可以处理大约6个域。我们必须处理超过32 000个域名。我们需要提高性能,因为这种多线程是可取的。
所以我开始编程任务,在spring等创建一个线程池...然后我意识到等待EMERGENCY_AUDIT_STOP_LIMIT如果计数器运行多个线程我怎么能这样做...没有任何回调。所以我尝试使用Callable而不是Runnable,所以我正在使用Future,然后我得出结论WTH我在思考,未来将阻止它的future.get()方法所以我将最终结束是一种方法,与我原来的实现一样慢或慢。
所以这是我的道路,我现在有点被阻止,Runnable不能抛出异常,所以将计数器传递给任务也不会工作,Callable会阻塞,所以也没有选择。< / p>
如果任何多线程大师有一个想法,我将非常感激。下面是我最近的尝试,它没有被打破,但和我上面的方法一样慢。
@Override
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void auditAllDomainConfigurationStatuses() throws InterruptedException, ExecutionException {
logger.info("Starting audit of all domain configuration statusses");
int errorStatusCounter = 0;
Map<SubdomainRegistryStatus, List<String>> domainsByStatus = new HashMap<SubdomainRegistryStatus, List<String>>();
List<DomainConfigurationStatus> domains = domainConfigurationStatusDao.findAll();
for (DomainConfigurationStatus domainConfigurationStatus : domains) {
try {
Future<Integer> futureResult = taskExecutor.submit(new DomainConfigurationAuditTask(errorStatusCounter, domainConfigurationStatusAuditor, domainConfigurationStatus.getId(), domainsByStatus, EMERGENCY_AUDIT_STOP_LIMIT));
futureResult.get();
}
catch (Exception e) {
logger.error("Emergency audit stop more then " + EMERGENCY_AUDIT_STOP_LIMIT + " records went into status ERROR");
mailEmergencyDomainConfigurationStatusAuditStop();
return;
}
}
mailDomainConfigurationStatusReport(domainsByStatus);
logger.info("Audit of all domain configuration statusses completed");
}
答案 0 :(得分:1)
这是一个非常简单的解决方案。基本上,完成某些工作(即DNS查找)的任务是完全隔离和可并行化的。成功或失败之后的部分工作是将成功布尔值提交给另一个{em>固定大小为1 的ExecutoService
,这可以执行您想要的任何错误条件检查。
在这种情况下,它只是递增一个连续错误的整数,直到达到最大条件,然后设置一个错误条件,工作线程(DNS查找)全部检查首先是一个快速失败的方法,所以所有排队在满足错误条件后,任务将快速退出。
这样就可以非常简单地在多线程场景中跟踪连续的错误,就像你对响应进行单线程检查一样
我可以想到使用Java 8的CompletableFuture
更优雅的解决方案,但听起来像是在桌面之外
package so.thread.errcondition;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static Random rand = new Random();
public static ExecutorService workers = Executors.newFixedThreadPool(5);
// NOTE, this executor has a FIXED size of 1 for in-order processing
public static ExecutorService watcher = Executors.newFixedThreadPool(1);
public static AtomicBoolean errorCondition = new AtomicBoolean(false);
public static AtomicInteger errorCount = new AtomicInteger(0);
public static Integer MAX_ERRORS = 5;
public static void main(String[] args) throws Exception {
int jobs = 1000;
for (int i = 0; i < jobs; i++) {
workers.submit(getWork());
}
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
}
// parallelizable task, the number of parallel workers is irrelevant
public static Runnable getWork() {
return new Runnable() {
@Override
public void run() {
// fail fast
if (errorCondition.get()) {
System.out.println("%%% MAX_ERRORS of [" + MAX_ERRORS + "] occurred, skipping task");
return;
}
// do work
if (rand.nextBoolean()) {
// GOOD JOB
System.out.println("+++ GOOD RESULT");
submitDoneTask(true);
} else {
// ERROR
System.out.println("*** BAD RESULT");
submitDoneTask(false);
}
}
};
}
public static void submitDoneTask(final boolean success) {
watcher.submit(new Runnable() {
@Override
public void run() {
if (!errorCondition.get() && success) {
errorCount.set(0);
} else {
int errors = errorCount.incrementAndGet();
if (errors >= MAX_ERRORS) {
errorCondition.set(true);
}
}
}
});
}
}