我使用累加器并想知道这些对象是否是线程安全的?
accumInt
是一种AccumulatorParam<Integer>
。
// Current value accumInt -> 6
AccumulatorThread t1 = new AccumulatorThread();
t1.setAccum(accumInt);
t1.setValueToAdd(5);
AccumulatorThread t2 = new AccumulatorThread();
t2.setAccum(accumInt);
t2.setValueToAdd(7);
new Thread(t1).start();
new Thread(t2).start();
System.out.println(accumInt.value()); // 11 or 13 or 18
AccumlatorThread
上课:
class AccumulatorThread implements Runnable {
Accumulator<Integer> accum;
Integer valueToAdd;
public Integer getValueToAdd() {
return valueToAdd;
}
public void setValueToAdd(Integer valueToAdd) {
this.valueToAdd = valueToAdd;
}
public Accumulator<Integer> getAccum() {
return accum;
}
public void setAccum(Accumulator<Integer> accum) {
this.accum = accum;
}
public void run() {
System.out.println("Value to Add in Thread : "+valueToAdd);
accum.add(valueToAdd);
}
}
该行为表明它不是线程安全的。我错过了什么吗?
答案 0 :(得分:5)
OOC你为什么要在同一个程序中设置和读取累加器?累加器通常由工作线程添加,并且只能由驱动程序线程读取。
Worker1: accumulator.add(increment)
Worker2: accumulator.add(someOtherIncrement)
Driver: println(accumulator.value)
现在,您正在询问有关在驱动程序的不同线程中设置/读取值的多线程。为了什么目的?在这种情况下,只需使用本地JVM AtomicInteger
或AtomicLong
。
累加器是仅通过关联操作“添加”的变量,因此可以并行有效地支持。
答案 1 :(得分:4)
累加器不是线程安全的。只有SparkContext
可用于多个线程。
答案 2 :(得分:1)
要扩展@javadba和@zsxwing的其他两个重要答案。
我对Apache Spark的理解是它们可能是也可能不是线程安全的。 不真的很重要。由于司机在很远的地方&#34;从它的工作者(他们通常通过网络或至少在JVM之间 - 彼此通信 - 除非它是本地模式)对累加器的所有更新都到达逐个处理的消息,从而确保单线程更新到累加器。
答案 3 :(得分:0)
累加器不是线程安全的,实际上它们不需要是线程安全的。对于执行程序,累加器是只写变量,它们可以由执行程序添加,并且可以由驱动程序读取。驱动程序使用DAGScheduler.updateAccumulators方法在任务完成后更新累加器的值,并且仅从运行调度循环的线程调用此方法。一次只处理一个任务完成事件。这就是为什么不需要累加器是线程安全的。