Mr *_*der 6 java parallel-processing concurrency multithreading biginteger
我正在尝试计算一些大数字.为了加快计算速度,我想利用多线程.每个线程都应该计算一个数字,最后计算一个总和.
我曾经看过一些与a SumThread
和a Collector
有关的东西,如下所示:
public BigInteger compute(int p) {
Collector c = new Collector(p);
for(T element : Collection<T> bigCollection) {
new SumThread(c) {
@Override
protected void doTheJob() {
long big = someVeryComplexCalculation(element, ...); //n!
receive(BigInteger.valueOf(big));
}
}
}
if(collector.isReady())
return collector.getResult();
return null;
}
public class Collector {
private int numberOfProcesses;
private int numberOfAllowedProcesses;
private BigInteger result;
public Collector(int n) {
numberOfAllowedProcesses = n;
numberOfProcesses = 0;
result = BigInteger.ZERO;
}
synchronized public void enter() throws InterruptedException {
if (numberOfProcesses == numberOfAllowedProcesses) wait();
numberOfProcesses++;
}
synchronized public void leave() {
numberOfProcesses--;
notify();
}
synchronized public void register(BigInteger v) {
result = result.add(v);
}
synchronized public boolean isReady() throws InterruptedException {
while (numberOfProcesses > 0) wait();
return true;
}
...
}
public abstract class SumThread extends Thread {
private Collector collector;
public SumThread(Collector c) throws InterruptedException {
collector = c;
collector.enter();
}
abstract protected void doTheJob(); //complex calculations can be done in here
public void receive(BigInteger t) {
collector.register(t);
}
public void run() {
doTheJob();
collector.leave();
}
}
Run Code Online (Sandbox Code Playgroud)
我以为我可以轻松地通过使用ExecutorService
而不是Thread
像以下那样使用新的s 来超越这个:
public BigInteger compute(int p) {
ExecutorService pool = Executors.newFixedThreadPool(p);
Future<BigInteger>[] futures = new Future<BigInteger>[bigCollection.size()];
int i = 0;
for(T element : Collection<T> bigCollection) {
futures[i++] = p.submit(new Callable<BigInteger>() {
@Override
public BigInteger call() {
long big = someVeryComplexCalculation(element, ...); //n!
return BigInteger.valueOf(big);
}
}
}
// or with ExecutorCompletionService, but the loop remains I guess
BigInteger res = BigInteger.ZERO
for(Future<BigInteger> f : futures)
res = res.add(f.get());
return res;
}
Run Code Online (Sandbox Code Playgroud)
但是,此代码无法胜过SumThread
- Collector
解决方案.我也看过一些事情LongAdder
,但我需要一些加法器BigInteger
...
我的问题是:同时计算金额的最佳方法是什么?它是上述之一还是有完全不同(但更好)的方式?
正如您所提到的那样LongAdder
,在Java-8中添加并使用有效的最终变量,我假设您使用的是Java-8.在此版本中,解决任务的最佳方法是使用Stream API:
BigInteger result = bigCollection.parallelStream()
.map(e -> BigInteger.valueOf(someVeryComplexCalculation(e, ...)))
.reduce(BigInteger.ZERO, BigInteger::add);
Run Code Online (Sandbox Code Playgroud)
您的问题是经典的map-reduce任务,您应该在其中转换某些集合的每个元素,然后将各个转换的结果合并到最终结果中.Stream API能够非常有效地并行化这些任务,而无需任何手动工作.在Oracle JDK中,任务在公共ForkJoinPool池中执行,默认情况下会创建与您拥有的CPU核心数一样多的线程.