2011-04-11 9 views
1

아래는 코드의 일부입니다. 나는 "알림 1"이 실제로 기다리고있는 다른 기능을 깨울 수없는 이유를 혼란스럽게 생각합니다. 하나의 스레드가 객체에 대해 동기화 된 메소드를 실행할 때 첫 번째 스레드가 객체로 완료 될 때까지 동일한 객체 블록 (실행 일시 중단)에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드는 . 자바 멀티 스레딩 문제

왜 결과가되지 않습니다 : 대기, notify1, 대기 마감, notify2, . . .

는 대신은 다음과 같습니다 대기, notify1, notify2, notify2, . . . notify2는 는 가 는 는 을 대기 이동 기다려 건너 대기 이동 3, 대기 완료 통지, 통지 2. . .

코드 { . . .

MultiThreadContent m; 

    void divideToParts(File testFile,FileInputStream fileInputStream, Object hashMachine) throws IOException, InterruptedException{ 

     . 
     . 
     . 
     //run from here 
     m = new MultiThreadContent(fileInputStream,(int)temp23,(int) (testFile.length()%temp23), numberOfParts, hashMachine); 
     new Thread(new Read()).start(); 
     m.update(); 
    } 

    class Read implements Runnable{ 
     @Override 
     public void run() { 
      try { 
       m.read(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    class MultiThreadContent{ 

     . 
     . 
     . 


     boolean preNotReady=true; 
     boolean updateNotFinished; 

     //read{ 
      public synchronized void read() throws InterruptedException{ 
       //initial{ 
        readNextBlock(); 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 1");//d 
        if(finishedRead!=true) 
        { 
         readNextBlock(); 
         read_wait(); 
        } 
        else 
         return; 
       //} 
       while(finishedRead!=true){ 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 2");//d 
        readNextBlock(); 
        read_wait(); 
       } 
       //closing{ 
        preBlock=nextBlock; 
        read_notify(); 
        System.out.println("notify 3");//d 
       //} 
      } 
      void read_notify(){ 
       preNotReady=false; 
       notifyAll(); 
      } 
      void read_wait() throws InterruptedException{ 
       if(updateNotFinished==true) 
       { 
        wait(); 
        System.out.println("wait for update");//d 
       } 
       preNotReady=true; 
      } 
     //} 


     //update{ 
      public synchronized void update() throws InterruptedException{ 
       for (int i = 0; i < totalParts; i++) { 
        update_wait(); 
        divideToParts_update(hashMachine, preBlock); 
        update_notify(); 
       } 
      } 
      void update_notify(){ 
       updateNotFinished=false; 
       notifyAll(); 
      } 
      void update_wait() throws InterruptedException{ 
       if(preNotReady){ 
        System.out.println("wait");//d 
        wait(); 
        System.out.println("wait finish");//d 
       } 
       updateNotFinished=true; 
       System.out.println("skip wait");//d 
      } 
     //} 
    } 
} 
+1

'finishedRead'가 정의되지 않았습니까? 이 모든 코드입니까? – Kevin

+0

코드의 일부입니다. 나는 notifyAll이 "notify 1"에서 기다리고있는 다른 함수를 깨울 수없는 이유를 혼란 스럽다. – micahli123

답변

0

이 문제가 발생했는지는 확실치 않지만 확실하게 문제가 될 수 있습니다. .wait()에 대한 모든 호출은 while 루프로 묶어야합니다. 기다려야하는 전화()는 무작위로 일어날 수 있습니다. documentation

는 "인수가 1 개의 버젼에서는, 인터럽트와 가짜를 깨우는이 가능하며,이 메소드는 항상 루프에서 사용되어야한다 :"당신은 동기화 된 블록을 왼쪽하지 않았기 때문에

+0

당신의 가르침에 감사드립니다! 나는 이것이 문제가 될 수 있다고 생각한다. 그러나 심지어 나는이 문제를 여전히 해결했습니다. – micahli123

1

이유는 . read_wait 메소드는 updateNotFinished가 기본값으로 false로 초기화되기 때문에 절대로 if 블록을 입력하지 않습니다. read_wait는 절대로 if 블록을 입력하지 않으므로 finishedRead!=true에서 계속 루프됩니다. 해당 메소드와 동기화 된 블록이 종료 될 때까지 절대로 모니터를 보류하지 않습니다.

일단 완료되면 잠금을 사용할 수 있고 다른 스레드는 올바르게 작동합니다.

내가 무슨 말을하고 있는지 테스트하려면 초기화시 updateNotFinished = true을 설정해보십시오.

+0

@ John V. 그러나 updateNotFinished = true; update_wait()에서. 그러나 read()의 nofifyAll이 update_wait()에서 wait()를 깨우지 않으므로 updateNotFinished = true; 명령이 늦게까지 실행되지 않습니다 .. – micahli123

+1

@ micahli123보고있는 문제는 단순히 read()의 스레드가 종료되지 않기 때문입니다.동기화 된 메소드는 상호 배제를 보장하며 notifyAll은 동기화 된 블록에 다른 스레드가 없을 때 스레드를 깨울뿐입니다. 동기화 된 블록을 떠나지 않으므로 대기중인 모든 스레드는 해당 블록을 종료 할 때까지 절대로 깨우지 않습니다. 기본적으로 update_wait의 updateNotFinished = true는 첫 번째 스레드가 완료 될 때까지 호출되지 않습니다. 내가 테스트를 시도 –

+0

@ 존 V. 후, notify1 작업을 수행합니다 ' 이 가 대기를 건너 기다 건너 뛰기 대기 건너 뛰기 대기 건너 뛰기 대기 건너 뛰기 을 완료 기다려 1 통지 기다려야하지만, 난 여전히되지 않는 이유는 무엇 notify1 모른다 내 예를 들어 ... – micahli123

0

새로운 동시성 라이브러리는 wait()/notify() 라이브러리보다 훨씬 사용하기 쉽습니다. 이러한 라이브러리는 이유 때문에 추가되었으며 학습 가치가 있습니다. 다음은 코드를 단순화하는 방법의 예입니다.

String filename = ... 
ExecutorService es = Executors.newFixedThreadPool(5); 
FileInputStream fis = new FileInputStream(filename); 

while (true) { 
    final byte[] buffer = new byte[8 * 1024]; 
    final int len = fis.read(buffer); 
    if (len < 0) break; 
    es.submit(new Runnable() { 
     public void run() { 
      process(buffer, len); 
     } 
    }); 
} 
fis.close(); 
es.shutdown(); 
es.awaitTermination(60, TimeUnit.MINUTES); 
+1

놀랍습니다. 나는 그것을 시도 할 것이다. 똑같은데. 좀 더 유연 해 보입니다. – micahli123