【发布时间】:2015-07-08 17:54:29
【问题描述】:
这是一个java并发问题。需要完成 10 个工作,每个工作将有 32 个工作线程。工作线程会增加一个计数器。一旦计数器为 32,则表示此工作已完成,然后清理计数器图。从控制台输出,我预计将输出 10 个“完成”,池大小为 0,counterThread 大小为 0。
问题是:
大多数时候,“池大小:0 和 countThreadMap 大小:3”将是 打印出来。甚至那些所有线程都消失了,但 3 个工作没有 完成了。
有一段时间,我在第27行看到nullpointerexception。我用过ConcurrentHashMap和AtomicLong,为什么还有并发 例外。
谢谢
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;
public class Test {
final ConcurrentHashMap<Long, AtomicLong[]> countThreadMap = new ConcurrentHashMap<Long, AtomicLong[]>();
final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
final ThreadPoolExecutor tPoolExecutor = ((ThreadPoolExecutor) cachedThreadPool);
public void doJob(final Long batchIterationTime) {
for (int i = 0; i < 32; i++) {
Thread workerThread = new Thread(new Runnable() {
@Override
public void run() {
if (countThreadMap.get(batchIterationTime) == null) {
AtomicLong[] atomicThreadCountArr = new AtomicLong[2];
atomicThreadCountArr[0] = new AtomicLong(1);
atomicThreadCountArr[1] = new AtomicLong(System.currentTimeMillis()); //start up time
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
} else {
AtomicLong[] atomicThreadCountArr = countThreadMap.get(batchIterationTime);
atomicThreadCountArr[0].getAndAdd(1);
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
}
if (countThreadMap.get(batchIterationTime)[0].get() == 32) {
System.out.println("done");
countThreadMap.remove(batchIterationTime);
}
}
});
tPoolExecutor.execute(workerThread);
}
}
public void report(){
while(tPoolExecutor.getActiveCount() != 0){
//
}
System.out.println("pool size: "+ tPoolExecutor.getActiveCount() + " and countThreadMap size:"+countThreadMap.size());
}
public static void main(String[] args) throws Exception {
Test test = new Test();
for (int i = 0; i < 10; i++) {
Long batchIterationTime = System.currentTimeMillis();
test.doJob(batchIterationTime);
}
test.report();
System.out.println("All Jobs are done");
}
}
【问题讨论】:
-
你知道report() 方法不是原子的,对吧?不同尺寸的检查之间存在竞争。
-
你的意思是这条线不是线程安全的吗? tPoolExecutor.getActiveCount()
-
report()中的 while 循环...这真的是一个紧密的循环,还是//所在的位置有实际代码?如果这是一个紧密的循环 - 这不是您等待线程完成的方式。 -
另外,仅仅因为您使用
ConcurrentHashMap并不意味着您正在以线程安全的方式使用它。您没有正确同步访问(查找 check-then-act)。这也是一个相当抽象的问题,可能是XY problem -
@EdwardChen
put和get是线程安全的,但调用get然后再调用put期望地图的状态在此期间保持不变是错误的。只需查看 check-then-act,此代码已严重损坏。如果您能描述(使用文字,而不是代码)您的目标是什么,那将会很有帮助。假设您上面的代码是完美的并且可以正常工作,您将如何处理它?在我看来,那个是重要的问题。
标签: java multithreading concurrency