结算类具有与国家明智结算相关的所有逻辑。它从数据库中获取结果,然后向用户收费。计费类实现了Runnable。我想根据国家参数并行执行Billing,这样就可以非常快速地收取大量用户(500万+)。现在需要花费数小时才能完成。
我正在尝试实现ThreadPoolExecutor来执行Billing类但我很困惑怎么办?以下有什么区别或我做错了什么?请建议!!共有20个国家,但我只在这里粘贴了5.
//for 20 countries ThreadPoolExecutor (20,20,20.......)????
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy());
executor.execute(new Billing("UK"));
executor.execute(new Billing("USA"));
executor.execute(new Billing("Germany"));
executor.execute(new Billing("Spain"));
executor.execute(new Billing("Italy"));
OR
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy());
for(int i=0;i<5;i++) // for 20 countries i<20??
{
executor.execute(new Billing("UK"));
executor.execute(new Billing("USA"));
executor.execute(new Billing("Germany"));
executor.execute(new Billing("Spain"));
executor.execute(new Billing("Italy"));
}
while (! executor.isTerminated()) {
try{
executor.awaitTermination(100, TimeUnit.SECONDS);
}catch(InterruptedException iE)
{
iE.printStackTrace();
System.out.println("Executor Exception: "+ iE);
}
提前致谢!!
答案 0 :(得分:1)
循环解决方案似乎不对。无需多次执行相同的Runnable
。
您将ThreadPoolExecutor
和corePoolSize
都设置为maximumPoolSize
来实例化5
,这意味着执行程序会将池中的线程数保持为{{1}即使他们闲着也是如此。它还说池中只有5
个线程。
有了这个,你可以期望大多数5
线程并行执行任务(5
对象)。
当您继续使用Billing
方法向Billing
提交executor
个对象时,它们会被添加到您提供的execute
中。此队列的大小为ArrayBlockingQueue
。在某些情况下,队列可能已处于其最大容量且无法执行更多任务,在这种情况下,任务将被拒绝并提供给10
构造函数中提供的RejectedExecutionHandler
。它的工作是使用实现的方法ThreadPoolExecutor
来处理被拒绝的任务。
如果您想查找是否有任何被拒绝的任务,您必须提供自己的rejectedExecution
,而不是使用默认的RejectedExecutionHandler
。你可以这样做:
ThreadPoolExecutor.CallerRunsPolicy
答案 1 :(得分:1)
首先:忘记循环
for(int i=0;i<5;i++) // for 20 countries i<20??
{
executor.execute(new Billing("UK"));
executor.execute(new Billing("USA"));
executor.execute(new Billing("Germany"));
executor.execute(new Billing("Spain"));
executor.execute(new Billing("Italy"));
}
这会多次循环所有账单。
正确的做法是在第一个片段中:
executor.execute(new Billing("UK"));
executor.execute(new Billing("USA"));
executor.execute(new Billing("Germany"));
executor.execute(new Billing("Spain"));
executor.execute(new Billing("Italy"));
另一个错误在于终止检查:
while (! executor.isTerminated()) {
try{
executor.awaitTermination(100, TimeUnit.SECONDS);
}catch(InterruptedException iE)
{
iE.printStackTrace();
System.out.println("Executor Exception: "+ iE);
}
}
Executor.awaitTermination
的javadoc说:
阻止所有任务在关闭请求后完成执行,
但您永远不会发出关机请求。
在您的情况下,您可以使用ExecutorCompletionService
,如下所示:
CompletionService<String> ecs = new ExecutorCompletionService<String>(executor);
List<String> countries= Arrays.asList("UK","USA","Germany","Spain","Italy");
for(String country : countries) {
ecs.submit(new Billing(country),country);
}
// wait for completion
for(int i=0;i<countries.size();i++){
ecs.take(); // wait for next country completion
}
// all work completed, shutdown
executor.shutdownNow();
答案 2 :(得分:0)
我不确定你是否了解循环是如何工作的。不同之处在于,第二个代码块将在每个列出的国家/地区运行5次计费。
答案 3 :(得分:0)
假设您正在讨论代码的for
循环部分,那么它的工作原理并不明显。
理想情况下,循环看起来像这样:
for(String country : countryCollection) {
executor.execute(new Billing(country));
}
答案 4 :(得分:0)
您是否考虑过使用enum
?
static class Billing implements Runnable {
enum Country {
UK,
USA,
Germany,
Spain,
Italy;
}
public Billing(Country country) {
}
@Override
public void run() {
}
}
public void test() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10),
new ThreadPoolExecutor.CallerRunsPolicy());
for ( Billing.Country country : Billing.Country.values() ) {
executor.execute(new Billing(country));
}
}
答案 5 :(得分:0)
考虑实施此问题的另一种方法是查看The Fork/Join Framework。这似乎真的可以从钢铁工作中受益。例如,你可以看起来相当干净地打破它。这基本上允许您分解用户或用户子集的计费任务,而不是让一个看似代表一个国家的线程通过其所有计费工作。
您可以找到图书馆的链接:here if you are using a version of Java < 7