0

를 생산하는 내 문제의 소스 인 ConcurrentApp 클래스 내 코드입니다 : 일부를 포함하는 클래스 DCP에 대한자바 프로그램의 실행 스레드를 더 추가하고 여기에 다른 결과

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"); 
    } 
} 

및 관련 코드 도우미 기능, 여기에 있습니다 :

public class DCP<E> extends CondInd<E> { 
    public final int R;    //assumed maximum # of nodes blocking any node from target 
    public ArrayList <Integer> PA; //set of all parents of the target node (should be static) 
    //public Node NULL;  //NULL is model with no parents of target (should be final static) 
    public E scoreType = null; 
    public ScoringFunction<? super E> scoringFunction; 

    public double calcScore(E sT, Set<Integer> parentIndices) { 
     ArrayList<Integer> list = new ArrayList<Integer>(parentIndices); 
     return this.scoringFunction.score(sT, list); 
    } 

    public double calcScore(E sT, ArrayList<Integer> parentIndices) { 
     return this.scoringFunction.score(sT, parentIndices); 
    } 


    //helper for actual subsets method 
    private void getSubsets(ArrayList<Integer> input, int length, int start_index, Set<Integer> acc, ArrayList<Set<Integer>> sol){ 
     //base case 
     if (acc.size() == length){ 
      sol.add(new HashSet<>(acc)); 
      return; 
     } 
     //recursive solution 
     if (start_index == input.size()) return; 
     int x = input.get(start_index); 
     acc.add(x); 
     //first recursion 
     getSubsets(input, length, start_index+1, acc, sol); 
     acc.remove(x); 
     //second recursion, after x removed 
     getSubsets(input, length, start_index+1, acc, sol); 
    } 

    //different arguments and returns a list of subsets 
    public ArrayList<Set<Integer>> getSubsets(ArrayList<Integer> input, int length){ 
     ArrayList<Set<Integer>> sol = new ArrayList<>(); 
     getSubsets(input, length, 0, new HashSet<Integer>(), sol); 
     return sol; 
    } 

    //different arguments and returns a list of subsets 
    public ArrayList<Set<Integer>> getSubsets(Set<Integer> input, int length){ 
     ArrayList<Set<Integer>> sol = new ArrayList<>(); 
     ArrayList<Integer> copy = new ArrayList<Integer>(input); 
     getSubsets(copy, length, 0, new HashSet<Integer>(), sol); 
     return sol; 
    } 


    //removes the element from the input that increases the score by the highest value 
    public void increaseScore(Set<Integer> input){ 
     int index = -1; 
     double score = calcScore(scoreType,input); 
     List<Integer> list = new ArrayList<Integer>(input); 
     for (Integer element : list) { 
      ArrayList<Integer> copy_list = new ArrayList<Integer>(list); 
      copy_list.remove(element); 
      if (calcScore(scoreType,copy_list) > score){ 
       index = list.indexOf(element); 
       score = calcScore(scoreType,copy_list); 
      } 
     } 
     if (index != -1) 
      input.remove(list.get(index)); 
    } 

    public DCP(int maximumNodes, E scoreType, ScoringFunction<? super E> scoringFunction, ArrayList<Integer> parents){ 
     this.R = maximumNodes; 
     this.scoreType = scoreType; 
     this.scoringFunction = scoringFunction; 
     this.PA = parents; 
    } 
} 

내가 스레드 = 1, 내 인쇄 제표를 기준으로 내 콘솔에 다음과 같은 출력을 받게과 ConcurrentApp에 ​​내 코드를 실행 :

All tasks submitted 
0 WAS REMOVED by thread 1 
1 WAS REMOVED by thread 0 
2 WAS REMOVED by thread 0 
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 

여기서 첫 번째 숫자는 내 목록에서 제거 된 정수에 해당합니다 (예 : "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을 주 목록에서 삭제해야한다고 잘못 결정하기 때문에 [7, 8] 대신 [7]을 사용하여 결과가 변경된다는 것입니다. 나는 잠금 필드에 정적을 추가하여 다중 스레드 삭제이 문제를 해결 :

private static Object lock = new Object(); 

그러나, 지금은 내가 스레드의 수를 증가 할 때 런타임이 변경되지 않는 문제가 있습니다. 정적 첨가 후 실> = 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 

수는 런타임이 향상되지 않고 I 정확한 결과를 얻는다. 이 결과와 런타임은 1 개의 thread를 사용하든 많든간에 정확히 동일합니다.

질문 : 제가보기에는 두 가지 해결책이 있습니다 :

1) 잠금에 static 키워드를 제거하고를 건너 다른 스레드를 말할 제거를 수행하는 스레드에 대한 방법을 찾아 제거 된 값

2) 정적 키워드를 유지하고 더 많은 정보가있을 때 내 프로그램이 오직 하나의 스레드 만 사용하는 이유를 알아보십시오.

모든 아이디어를 매우 높이 평가합니다.

+5

모든 코드가이 질문과 관련이 있다고 생각하기는 어렵습니다. 그것을 [mcve]로 축소 할 수 있습니까? – shmosel

+0

@shmosel 첫 번째 코드 블록은 문제에 필요한 주요 코드입니다. 이전에 유사한 코드를 게시 한 적이 있으며, 작업을 쉽게하기 위해 두 번째 코드 블록을 포함 시키라는 지시를 받았습니다. 첫 번째 코드 블록에 초점을 맞추고 첫 번째 블록의 일부 기능/클래스를 이해해야하는 경우 두 번째 코드 블록을 참조하십시오. 이것은 완전한 예제지만 믿을만한 예제는 코드를 실행하는 데 필요한 다양한 패키지와 종속성으로 인해 훨씬 ​​많은 코드가 필요합니다. –

답변

0

(코드의 일부를 게시하는 법을 배워야합니다. 친구).

내 진단 : processRemoval 전체 세트, 세트가 첫 번째 스레드에 의해서만 처리되고 왜 그렇게 당연을 처리하기 전에 스레드 의 나머지 부분과 동기화되어 있기 때문에 프로그램이 멀티 스레딩에서 동일하게 동작합니다.

이러한 경우 일반적인 방법은 각 항목을 처리하기 전에 스레드를 동기화하는 것입니다.따라서 synchronize 블록 루프로 이동해야합니다.

그러나이 경우 루프 내에서 세트를 수정하면 ConcurrentModificationException이 생성 될 수 있습니다. 이를 방지하려면 HashSet을 사용하여 Set의 동시 구현으로 대체하는 것이 좋습니다. 예를 들어 ConcurrentSkipListSet 또는 CopyOnWriteArraySet과 같이 선택하십시오.

+0

입력을 감사하십시오. 나는'synchronize' 키워드를 옮겨 보았지만 아무 것도하지 않는 것처럼 보였습니다 (for 루프로 옮기고'ProcessRemoval'에서 다른 곳을 시도했습니다). 또한 여러 스레드가 액세스하는 내 세트가 모두'ConcurrentHashMap'의 스레드 안전 구현에 의해 지원되기 때문에'ConcurrentModificationException'도 얻지 못합니다. –