2011-11-10 2 views
1

파일을 서버에 업로드하는 데 다중 스레드를 사용하고 있습니다. Java 애플릿은 UI를 표시합니다. 처음에는 ThreadPoolExecutor &을 사용하여 5 개의 스레드를 시작하여 5 개의 파일을 할당합니다. 업로드가 끝나면 서버에서 알림을받습니다. 스레드가 실행을 완료하면 모든 파일이 서버에 업로드 될 때까지 새로운 스레드가 파일과 함께 할당됩니다.ThreadPoolExecutor 구현 문제

기본 코드 구조를 다음과 같이

I> 업로드 기능을 처리하기위한 책임이있는 자바 애플릿에서 호출되는 방법 startUpload는().

class Upload extends Runnable{ 


............................... 
.............................. 

public void startUpload() { 

............................... //other initialisations done 

    int waitTime = 500; 

    Random random = new Random(); 

    ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300)); 

    while (it.hasNext()) { 

       int time = random.nextInt(1000); 
       waitTime += time; 
       newFile = new File((String) it.next()); 

       executor.execute(new Runnable() { 

        @Override 
        public void run() { 

         try{ 
         Thread.sleep(wait); 
         } 
         catch(Exception e){ 
         } 
         processFile1(newFile); 
        } 
       }); 

      } 
      try { 
       Thread.sleep(waitTime); 
       executor.shutdown(); 
       executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS); 

      } catch (Exception e) { 
      } 

    } 

}

나는 현재 직면하고 문제.

i> UI는 모든 파일을 업로드 할 때만 업데이트됩니다. 중간 단계에서 UI는 매달린 상태에 있습니다. EDT가 막힌 상태로가는 것 같습니다.

같은 기능을 구현하기 위해 스레드 클래스, 알림/절전 모드를 사용할 때 UI 렌더링과 동일한 코드가 제대로 작동했습니다. 나는 블로그/기사에서 자바 버젼 5.0에서 멀티 쓰레딩을 구현하는 더 좋은 방법을 보았 기 때문에 코드를 ThreadPoolExecutor로 바꿨다.

ii> 위의 코드에서 wait()를 모두 제거하면 size 1KB (테스트 용) 인 여러 파일을 업로드 할 때 ThreadPoolExecutor에서 알아챈 또 다른 점은 다음 줄에서 새 파일이 할당됩니다 동일한 파일은 항상 여러 스레드에 의해 항상 업로드됩니다.

newFile = new File ((String) it.next());

그러나 run()을 사용하여 sleep()을 추가하면 여러 스레드가 다른 파일을 서버에 업로드합니다.

위의 코드에 구현 문제가 있습니까?

답변

2

문제 1 : newFile은 로컬 변수 대신 (정적?) 필드입니다.

newFile의 로컬 캡처가 루프마다 다르다는 것을 확인하십시오. 따라서, 그것은 더 좋아 보일 것입니다 :

while(it.hasNext()) { 
    final File newFile = new File((String) it.next()); 
    executor.execute(new Runnable() { 
    @Override 
    public void run() { 
     processFile1(newFile); // Local only to this iteration of the loop. 
    } 
    } 
} 

코드는 모두 Runnable 예에 싸여있다. 쓰레드가 무엇인지 알려주시겠습니까? EDT에 있다면 UI가 왜 잠겨 있는지 설명 할 수 있습니다.

작은 문제는 반복기에 제네릭이 없기 때문입니다. 이론적으로 String 컬렉션을 반복해야합니다.

Collection<String> listOfFiles = ... 

Iterator<String> it = listOfFiles.iterator(); 

while(it.hasNext()) { 
    String filename = it.next(); // No cast necessary 
} 
1

EDT 스레드를 차단하고 있기 때문에 UI가 정지합니다.

try { 
     Thread.sleep(waitTime); 
     executor.shutdown(); 
     executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS); 

    } catch (Exception e) { 
    } 

ExecutorService의 아이디어는 당신이 초기화 중에를 한 번 작성하고 프로그램이 종료 할 준비가 될 때까지 시스템을 종료하지 않을 것입니다 :이 코드는 범인입니다.이것의 관용구는 다음과 같을 수 있습니다

ExecutorService executor = Executors.newFixedThreadPool(5); 
Runtime.getRuntime().addShutdownHook(new Thread() { 
    public void run() { 
     executor.shutdown(); 
    } 
}); 

@ Bringer128 언급 한 바와 같이, 두 번째 문제는 당신이 정적 또는 멤버 변수의 값을 변경하고 새 위치로 File 참조를 할당되지 않는다는 사실에 기인한다. 코드가 정확하다면, final이 아닌 지역 변수가 내부 클래스에서 참조되지 않을 수도 있기 때문에 final File newFile으로 선언 된 newFile이 표시 될 것으로 예상됩니다.

+0

답장을 보내 주셔서 감사합니다. 나는 File을 Final & Local 변수로 변경했다. 내가 얻는 문제는 두 번 스레드가 같은 파일을 업로드하려고 시도하는 경우 (3 번 중 한 번)입니다. 문제는 기본적으로 스레드 동기화입니다. 서버 로그에서 두 개의 스레드가 동일한 파일을 업로드하려고 시도 했으므로 중복 요청이 있음을 알게되었습니다. 그것에 관한 어떤 제안? – chiranjib

+0

@chiranjib 내가 제안한 변화를 시험해 보라. newFile이 내 코드 에서처럼 로컬 변수라면 executor는 올바른 값을 얻을 것이다. executor가'newFile'에 액세스 할 때를 알 수 없으므로 메인 스레드가 그것을 갱신 할 때마다 동일하거나 다른 파일을 얻을 수 있습니다. – Bringer128