2012-02-22 2 views
2

업데이트를 잘못된 값을 반환 : 그것은이 지침의 단지 몇에 사용 된 몇 가지 코드에 깊이 묻혀 정적이었다. 제안 해 주셔서 감사합니다.자바의 HashMap 때때로 일부 스레드

우리는 스레드에서 하나의 HashMap를 (예 즉 여러 가지 이유로 나쁜) 사용하고 있지 않습니다. 각 thread에는, 독자적인 HashMap가 있습니다.

우리는 스레드에서 확장하는 클래스를 가지고있다. Thread.run()에서 우리는 HashMap을 만들고, 그 안에 키/값 쌍을 설정하고, 그 HashMap을 메서드에 전달합니다. 이 메서드는 HashMap에서 값을 가져 와서 문자열에 삽입하고 문자열을 반환합니다.

때때로 반환 된 문자열이 다른 값이 (여전히 Thread.run에서을()). 이것은 3 개 이상의 물리적 코어가있는 하드웨어에서만 발생합니다. 그리고 그것은 단지 두 번 일어났습니다 (우리가 로깅을 추가하기 전에 정확히 무슨 일이 일어나는지 정확히 알 수 있습니다).

왜 이런 일이 발생하는지 알고 싶습니다.

업데이트 : 전체 코드는 여기에 있습니다. ProcessTxt는 HashMap에서 값을 가져 와서 문자열에 넣는 것입니다.

import java.io.*; 
import java.util.HashMap; 

import junit.framework.TestCase; 
import net.windward.datasource.dom4j.Dom4jDataSource; 
import net.windward.xmlreport.ProcessReport; 
import net.windward.xmlreport.ProcessTxt; 

/** 
* Test calling from multiple threads 
*/ 
public class TestThreads extends TestCase { 

    private static String path = "."; 

    // JUnit stuff 
    public TestThreads(String name) { 
     super(name); 
    } 

    // Get logging going - called before any tests run 
    protected void setUp() throws Exception { 
     ProcessReport.init(); 
    } 

    // this is not necessary - called after any tests are run 
    protected void tearDown() { 
    } 

    private static final int NUM_THREADS = 100; 

    private boolean hadWithVarError = false; 


    /** 
    * Test that each thread has unique variables. 
    */ 
    public void testRunReportsWithVariables() throws Exception { 

     // run 10 threads 
     ReportThreadWithVariables[] th = new ReportThreadWithVariables[NUM_THREADS]; 
     for (int ind = 0; ind < NUM_THREADS; ind++) { 
      th[ind] = new ReportThreadWithVariables(this, ind); 
      th[ind].setName("Run " + ind); 
     } 
     for (int ind = 0; ind < NUM_THREADS; ind++) 
      th[ind].start(); 

     boolean allDone = false; 
     while (!allDone) { 
      Thread.sleep(100); 
      allDone = true; 
      for (int ind = 0; ind < NUM_THREADS; ind++) 
       if (th[ind].isAlive()) 
        allDone = false; 
     } 

     assertTrue(!hadWithVarError); 
    } 

    public static class ReportThreadWithVariables extends Thread { 

     private TestThreads obj; 
     private int num; 

     public ReportThreadWithVariables(TestThreads tt, int num) { 
      obj = tt; 
      this.num = num; 
     } 

     public void run() { 

      try{ 
       System.out.println("starting " + num); 
       ByteArrayOutputStream out = new ByteArrayOutputStream(); 
       ProcessTxt pt = new ProcessTxt(new FileInputStream(new File(path, "Thread_Test.docx")), out); 

       pt.processSetup(); 

       // don't use order1.xml, but need a datasource. 
       Dom4jDataSource datasource = new Dom4jDataSource(new FileInputStream(new File(path, "order1.xml"))); 
       HashMap map = new HashMap(); 
       map.put("num", new Integer(num)); 
       datasource.setMap(map); 
       pt.processData(datasource, ""); 

       pt.processComplete(); 
       String result = out.toString().trim(); 
       System.out.println("complete " + num + ", result = " + result); 

       String expected = "Number: " + num; 
       if (!result.equals(expected)) 
        obj.hadWithVarError = true; 
       assertEquals(expected, result); 
      } catch (Throwable e) { 
       obj.hadWithVarError = true; 
       e.printStackTrace(); 
      } 

     } 
    } 
} 

(형식 코드 편집)

+10

키 란 무엇입니까? 문제를 시연하는 짧지 만 완전한 프로그램은 실제로 도움이 될 것입니다. –

+0

어떤 유형의 값이 적합 할 수도 있습니다. 값이 다른 곳에서 참조되고 나중에 수정되는 객체를 포함 할 수 있습니까? – VeeArr

+0

몇 가지 샘플 코드를 추가하십시오. –

답변

1

전적으로 내가 뭔가 static 것을 가설려고하고 기록 된 내용에 코드의 부족을 감안할 및 기반. 즉, 라인을 따라 어딘가에 정적 멤버가 저장되거나 쓰여지고 있습니다.

+0

그게 우리가 찾은 첫 번째 것입니다. 또한이 문제는 매우 드물게 발생합니다. 4 코어 시스템에서 약 4 분 동안 실행해야합니다. 그리고 2 중핵 체계에 결코 일어나지 않는다. 나는 코드를 게시 할 것이다. –

0

NUM은 변경할 수 없으며 ReportThreadWithVariables는 스레드로부터 안전 외모 때문에 다른 변수 (문자열,지도) 지역이다. 문제는 내가 게시 한 것보다는 외부 개체를 호출하는 것입니다. 사용하는 클래스는 스레드 안전으로 문서화되어 있습니까?

예를 들어, javadoc of the processData method은 수행중인 것처럼 보이는 동일한 데이터 소스 (동일한 파일 이름)에 대해 여러 번 호출하면 안된다고 명시합니다.

PS : (안 관련은) 당신은 CountDownLatch를 대신 while 루프를 사용할 수 있습니다.