2011-12-28 14 views
8

Digamos que tengo 1000 archivos para leer y debido a algunos límites, quiero leer un máximo de 5 archivos en paralelo. Y, tan pronto como uno de ellos termine, quiero que comience uno nuevo.Cómo hacer un límite de hilo en Java

Tengo una función principal que tiene la lista de los archivos y trato de cambiar un contador cada vez que termina un hilo. pero no funciona!

¿Alguna sugerencia?

El siguiente es el bucle principal función

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

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

Respuesta

19

Engendrar hilos como este no es el camino a seguir. Utilice un ExecutorService y especifique que el grupo sea 5. Coloque todos los archivos en algo así como BlockingQueue u otra colección segura para subprocesos y todos los ejecutores pueden simplemente poll() hacerlo a voluntad.

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. No tiene sentido reinventar la rueda. Aunque creo que te refieres a ThreadPoolExecutor. No hay ExecutorPool en J2SE que yo sepa. –

+0

Jdk5 en adelante, hay muchas clases de inbuit para el manejo de subprocesos.Como kylar sugirió que es mejor usar Executorpool – kosa

+0

Sí, quise decir ExecutorService en realidad. Se corrigió y agregó el código fuente bruto aproximado para darle la esencia. – Kylar

0

Cualquiera sea el método que está utilizando para crear un nuevo hilo, incrementar un contador global, añadir una sentencia condicional en torno a la creación de hilos que si se ha alcanzado el límite, no cree un nuevo hilo, tal vez inserte los archivos en una cola (¿una lista?) y luego podría agregar otro enunciado condicional, después de crear un hilo, si hay elementos en la cola, para procesar esos elementos primero.

3

El enfoque en la respuesta de Kylar es el correcto. Utilice las clases ejecutadoras proporcionadas por las bibliotecas de clase de Java en lugar de implementar la agrupación de subprocesos usted mismo desde cero (mal).


Pero pensé que podría ser útil para discutir el código en su pregunta y por qué no funciona. (He llenado en algunas de las piezas que dejas a cabo lo mejor que pueda ...)

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); 
     } 
     // ... 
    } 
} 

bien, así que lo que está mal con esto? ¿Por qué no funciona?

Bueno, el primer problema es que en main está leyendo y escribiendo counter sin hacer ninguna sincronización. Supongo que también está siendo actualizado por los hilos de trabajo; de lo contrario, el código no tiene sentido. Entonces eso significa que hay una buena posibilidad de que los hilos principales no vean el resultado de las actualizaciones hechas por los hilos hijo. En otras palabras, while (counter > 5); podría ser un bucle infinito. (De hecho, esto es bastante probable. Se permite que el compilador JIT para generar código en el que el counter > 5 simplemente pone a prueba el valor de counter la izquierda en un registro después de la counter++; declaración anterior.

El segundo problema es que el bucle while (counter > 5); es un desperdicio increíble de recursos. Le está diciendo a la JVM que sondee una variable ... y hará esto potencialmente BILLONES de veces por segundo ... ejecutando un procesador (núcleo) a toda máquina. No debería hacer eso. va a poner en práctica este tipo de cosas usando primitivas de bajo nivel, se debe utilizar Object.wait() y Object.notify() métodos de Java; por ejemplo, las principales hilo espera, y cada subproceso de trabajo notifica

2

Yo. Puede usar un ExecutorService como un grupo de subprocesos Y una cola.

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); 
Cuestiones relacionadas