2011-12-28 2 views
8

읽을 파일이 1000 개이고 일부 제한 때문에 최대 5 개의 파일을 병렬로 읽으려고한다고 가정 해 봅니다. 그리고 그 중 하나가 끝나면 새로운 것을 시작하겠습니다.Java에서 스레드 제한을 만드는 방법

파일 목록이있는 주 기능이 있는데 한 스레드가 완료 될 때마다 카운터를 변경하려고합니다. 하지만 작동하지 않습니다!

의견이 있으십니까?

다음 새 스레드를 생성하는 데 사용하는 무엇이든 방법

for (final File filename : folder.listFiles()) { 

Object lock1 = new Object(); 
new myThread(filename, lock1).start(); 
counter++; 
while (counter > 5); 
} 

답변

19

이와 같은 산란 스레드는 이동 방법이 아닙니다. ExecutorService을 사용하고 풀을 5로 지정하십시오. BlockingQueue 또는 다른 스레드 안전 콜렉션과 같은 파일에 모든 파일을 넣으십시오. 실행중인 모든 파일은 그대로 poll()이 될 수 있습니다.

public class ThreadReader { 

    public static void main(String[] args) { 
     File f = null;//folder 
     final BlockingQueue<File> queue = new ArrayBlockingQueue<File>(1000); 
     for(File kid : f.listFiles()){ 
      queue.add(kid); 
     } 

     ExecutorService pool = Executors.newFixedThreadPool(5); 

     for(int i = 1; i <= 5; i++){ 
      Runnable r = new Runnable(){ 
       public void run() { 
        File workFile = null; 
        while((workFile = queue.poll()) != null){ 
         //work on the file. 
        } 
       } 
      }; 
      pool.execute(r); 
     } 
    } 
} 
+0

+1. 바퀴를 재발 명하는 감각이 없습니다. 그래도 ThreadPoolExecutor라고 생각합니다. 내가 아는 J2SE에는 ExecutorPool이 없다. –

+0

Jdk5 이후 스레드 처리를위한 많은 inbuit 클래스가 있습니다.kylar가 제안한 것처럼 Executorpool을 사용하는 것이 더 좋습니다 – kosa

+0

그래, 실제로 ExecutorService를 의미했습니다. 당신에게 요지를 제공하기 위해 고정 및 추가 슈퍼 거친 소스 코드. – Kylar

0

는, 세계적인 카운터를 증가 한계가 다음에 이르렀을 경우 그 쓰레드 생성 주위에 조건문을 추가 주요 기능 루프를하다 새 스레드를 만들지 말고 파일을 대기열 (목록)에 푸시 한 다음 스레드가 생성 된 후 대기열에 항목이있는 경우 해당 항목을 먼저 처리하기 위해 다른 조건문을 추가 할 수 있습니다.

3

Kylar의 대답은 올바른 것입니다. Java 클래스 라이브러리에서 제공하는 executor 클래스를 사용하면 처음부터 스레드 풀링을 구현하는 것이 아닙니다.


그러나 나는 당신의 질문에서 코드를 토론하는 것이 유용 할 수 있으며, 왜 효과가 없는지 생각했습니다. (내가 할 수있는 한 최선을 다한 부분을 채웠습니다 ...)

public class MyThread extends Thread { 

    private static int counter; 

    public MyThread(String fileName, Object lock) { 
     // Save parameters in instance variables 
    } 

    public void run() { 
     // Do stuff with instance variables 
     counter--; 
    } 

    public static void main(String[] args) { 
     // ... 
     for (final File filename : folder.listFiles()) { 
      Object lock1 = new Object(); 
      new MyThread(filename, lock1).start(); 
      counter++; 
      while (counter > 5); 
     } 
     // ... 
    } 
} 

그래, 뭐가 잘못 되었니? 왜 작동하지 않습니까?

첫 번째 문제는 main에서 동기화를 수행하지 않고 counter을 읽고 쓰고 있다는 것입니다. 나는 작업자 스레드에 의해 업데이트되고 있다고 가정한다. 코드는 그렇지 않다. 즉, 메인 쓰레드가 자식 쓰레드의 업데이트 결과를 보지 못하게 될 가능성이 있습니다. 즉, while (counter > 5);은 무한 루프 일 수 있습니다. (사실,이 꽤 가능성이있다. JIT 컴파일러는 counter > 5 단순히 이전 counter++; 문 뒤에 레지스터에 남아 counter의 값을 테스트하는 코드를 생성 할 수있다.

두 번째 문제는 당신 while (counter > 5); 루프가 있다는 것이다 믿을 수 없을만큼 많은 자원이 낭비되고 있습니다 .JVM에 변수를 폴링하라는 메시지가 표시됩니다. 그러면 1 초당 1 억 배의 처리량이 발생할 것입니다. 하나의 프로세서 (코어)를 실행해야합니다. 저급 프리미티브를 사용하여 이러한 종류의 작업을 구현하려면 자바의 Object.wait()Object.notify() 메서드를 사용해야합니다 (예 : 메인 스레드가 대기하고 각 작업자 스레드가 알립니다)

2

예 ExecutorService를 쓰레드 풀과 큐로 사용할 수 있습니다.

ExecutorService pool = Executors.newFixedThreadPool(5); 
File f = new File(args[0]); 

for (final File kid : f.listFiles()) { 
    pool.execute(new Runnable() { 
     @Override 
     public void run() { 
      process(kid); 
     } 
    }); 
} 
pool.shutdown(); 
// wait for them to finish for up to one minute. 
pool.awaitTermination(1, TimeUnit.MINUTES); 
관련 문제