Java程序运行时在添加更多线程时保持不变,并产生不同的结果
以下是我的ConcurrentApp类代码,这是我问题的根源:Java程序运行时在添加更多线程时保持不变,并产生不同的结果,java,multithreading,concurrency,locking,java.util.concurrent,Java,Multithreading,Concurrency,Locking,Java.util.concurrent,以下是我的ConcurrentApp类代码,这是我问题的根源: class Processor implements Runnable { private int id; private Integer interaction; private Set<Integer> subset; private Set<Integer> y; private Object lock = new Object(); public D
class Processor implements Runnable {
private int id;
private Integer interaction;
private Set<Integer> subset;
private Set<Integer> y;
private Object lock = new Object();
public DCP<BSN> dcp;
public Processor(int id, Integer interaction, Set<Integer> subset, DCP<BSN> dcp, Set<Integer> y) {
this.id = id;
this.interaction = interaction;
this.subset= subset;
this.dcp = dcp;
this.y = y;
}
public void run() {
//System.out.println("Starting: " + this.id);
if (this.y.contains(this.interaction)){
this.subset.add(this.interaction);
processRemoval(this.subset);
}
//System.out.println("Completed: " + this.id);
}
public void processRemoval(Set<Integer> collection){
synchronized(Processor.lock) {
for (Iterator<Integer> iter = this.y.iterator(); iter.hasNext(); ) {
int element = iter.next();
while(element != this.interaction){
element = iter.next();
}
this.dcp.increaseScore(collection);
if (!collection.contains(this.interaction)) {
System.out.println(element + " WAS REMOVED by thread " + this.id);
iter.remove();
}
}
}
}
}
public class ConcurrentApp {
public void multiRP (DCP<BSN> dcp, int threads) {
ConcurrentHashMap<Integer,Boolean> x = new ConcurrentHashMap<Integer,Boolean>();
ConcurrentHashMap<Integer,Boolean> z = new ConcurrentHashMap<Integer,Boolean>();
Set<Integer> y = (Set<Integer>) Collections.newSetFromMap(x);
y.addAll(dcp.PA);
Set<Integer> zeta = (Set<Integer>) Collections.newSetFromMap(z);
ExecutorService executor = Executors.newFixedThreadPool(threads);
int i =1;
while ((y.size() > i) && (i <= dcp.R)){
for (Iterator<Integer> iterator = y.iterator(); iterator.hasNext();){
zeta.addAll(y);
Integer interaction = iterator.next();
zeta.remove(interaction);
ArrayList<Set<Integer>> subsets = dcp.getSubsets(zeta, i);
for (int j = 0; j< subsets.size(); j++){
executor.submit(new Processor(j, interaction, subsets.get(j), dcp, y));
}
}
i++;
}
executor.shutdown();
System.out.println("All tasks submitted");
try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(y);
dcp.PA = new ArrayList<Integer>(y);
System.out.println("All tasks completed");
}
}
其中,第一个数字对应于从我的列表中删除的整数(例如,“0已被线程2删除”表示值0已从主列表y中删除)。这个输出是有意义的,因为每个需要删除的值都被删除了一次,并给出了预期的结果[7,8],这应该是本例中仅有的两个未删除的值
但是,当我使用>1个线程运行代码时,会得到以下输出:
All tasks submitted
0 WAS REMOVED by thread 2
1 WAS REMOVED by thread 1
2 WAS REMOVED by thread 0
2 WAS REMOVED by thread 1
3 WAS REMOVED by thread 1
3 WAS REMOVED by thread 2
4 WAS REMOVED by thread 0
4 WAS REMOVED by thread 1
5 WAS REMOVED by thread 0
5 WAS REMOVED by thread 1
6 WAS REMOVED by thread 0
6 WAS REMOVED by thread 1
7 WAS REMOVED by thread 1
7 WAS REMOVED by thread 2
8 WAS REMOVED by thread 1
8 WAS REMOVED by thread 0
[]
All tasks completed
Program completed in :0 seconds
如您所见,在某些情况下,相同的值被多次删除,因为多个线程决定需要删除该值。另一个问题是,这也会通过给我一个[]而不是[7,8]来改变我的结果,因为出于某种原因,当我使用多个线程时,程序错误地决定需要从主列表y中删除7和8。我通过向锁定字段添加static修复了多线程删除的问题:
private static Object lock = new Object();
但是,现在我有一个问题,当我增加线程数时,运行时不会改变。添加static后使用threads>=1的输出如下:
All tasks submitted
0 WAS REMOVED by thread 1
1 WAS REMOVED by thread 1
2 WAS REMOVED by thread 1
3 WAS REMOVED by thread 0
4 WAS REMOVED by thread 1
5 WAS REMOVED by thread 0
6 WAS REMOVED by thread 0
[7, 8]
All tasks completed
Program completed in :22 seconds
线程的数量并没有改善运行时,但我得到了正确的结果。无论我使用1个线程还是多个线程,这个结果和运行时都是完全相同的
问题:在我看来,有两种可能的解决方案:
1) 移除锁上的static关键字,并找到执行移除的线程告诉其他线程跳过移除的值的方法
2) 保留static关键字,找出为什么我的程序在有更多可用线程时只使用1个线程
任何想法都非常感谢 (我的朋友,你真的必须学会至少发布一部分代码)
我的诊断是:您的程序在多线程中的行为相同,因为processremovation
在处理整个集合之前正在与其余线程同步,所以难怪该集合仅由第一个线程处理
在这些情况下,通常的方法是在处理每个项目之前同步线程。因此,似乎应该将synchronize
块移动到循环中
但是,在这种情况下,您正在修改循环中的集合,这可能会产生
ConcurrentModificationException
。为了避免这种情况,我建议您也用另一个Set
的并发实现来代替使用HashSet
。例如,ConcurrentSkipListSet
或CopyOnWriteArraySet
,您可以选择。很难相信所有这些代码都与问题相关。你能试着把它简化成一个吗?@shmosel第一个代码块是解决这个问题所需要的主代码。我以前也发布过类似的代码,并且被告知还要包含第二个代码块,以使事情变得更简单。请关注第一个代码块,但当您需要了解第一个代码块中的某些函数/类时,请参考第二个代码块。我相信这是一个完整的示例,但是,由于运行代码所需的各种包和依赖关系,一个可验证的示例将需要更多的代码。我尝试移动synchronize
关键字,但似乎什么也没做(我将其移动到for循环中,并尝试在processremove
中的不同位置)。我也没有得到任何ConcurrentModificationException
,因为我的多线程访问集都有ConcurrentHashMap
private static Object lock = new Object();
All tasks submitted
0 WAS REMOVED by thread 1
1 WAS REMOVED by thread 1
2 WAS REMOVED by thread 1
3 WAS REMOVED by thread 0
4 WAS REMOVED by thread 1
5 WAS REMOVED by thread 0
6 WAS REMOVED by thread 0
[7, 8]
All tasks completed
Program completed in :22 seconds