2011-09-21 12 views
12

Estoy tratando de descargar varios archivos que coinciden con un patrón usando subprocesos. El patrón podría coincidir con 1 o 5 o 10 archivos de tamaños de diferencia.java descarga varios archivos usando subprocesos

digamos por simplicidad, el código real que se descargaría está en el método downloadFile() y fileNames es la lista de nombres de archivos que coinciden con el patrón. ¿Cómo hago esto usando hilos? Cada hilo descargará solo un archivo. ¿Es aconsejable crear un nuevo hilo dentro del ciclo for?

for (String name : fileNames){ 
    downloadFile(name, toPath); 
} 

Respuesta

31

Usted realmente desea utilizar un ExecutorService en lugar de hilos individuales, es mucho más limpio, probablemente con más prestaciones y le permitirá para cambiar las cosas con más facilidad posteriormente (el número de hilos de rosca, nombres, etc.):

ExecutorService pool = Executors.newFixedThreadPool(10); 
for (String name : fileNames) { 
    pool.submit(new DownloadTask(name, toPath)); 
} 
pool.shutdown(); 
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
// all tasks have now finished (unless an exception is thrown above) 

Y en algún otro lugar en su clase de definir el caballo de batalla real DownloadTask:

private static class DownloadTask implements Runnable { 

    private String name; 
    private final String toPath; 

    public DownloadTask(String name, String toPath) { 
     this.name = name; 
     this.toPath = toPath; 
    } 

    @Override 
    public void run() { 
     // surround with try-catch if downloadFile() throws something 
     downloadFile(name, toPath); 
    } 
} 

El método shutdown() tiene un nombre muy confuso, ya que "permitirá que las tareas presentadas anteriormente a ejecutar antes de terminar". awaitTermination() declara un InterruptedException que necesita manejar.

+0

Esto requiere que el método 'downloadFile()' se defina dentro de 'DownloadTask' (mi recomendación) o que se declare' static' cuando esté fuera. –

+0

'@Philipp Reichart' No se aceptarán nuevas tareas de descarga en la agrupación después de activar' shutdown'; lo evitaré si fuera usted. – Bitmap

+0

No es un problema ya que no se agregan nuevas tareas al grupo después de que se ha cerrado en este caso. Se supone que el primer fragmento de código vive en un método y crea un nuevo grupo en cada invocación. –

1

Sí, puede crear los hilos en línea.

for (final String name : fileNames){ 
    new Thread() { 
     public void run() { 
      downloadFile(name, toPath); 
     } 
    }.start(); 
} 
5

Sí, ciertamente podría crear un nuevo hilo dentro del for-loop. Algo como esto:

List<Thread> threads = new ArrayList<Thread>(); 
for (String name : fileNames) { 
    Thread t = new Thread() { 
    @Override public void run() { downloadFile(name, toPath); } 
    }; 
    t.start(); 
    threads.add(t); 
} 
for (Thread t : threads) { 
    t.join(); 
} 
// Now all files are downloaded. 

También debe considerar el uso de un Executor, por ejemplo, en un grupo de subprocesos creado por Executors.newFixedThreadPool(int).

+0

Usando el código anterior, ¿cómo puedo limitar el número de descargas simultáneas, digamos que solo quiero descargar 3 archivos a la vez? ¿Tiene un ejemplo de usar Executor – user373201

+0

@ user373201: siga el enlace que proporcioné a 'Executors.newFixedThreadPool (int)' y revise la respuesta de @Phillip Reichart. – maerics

1

Use Executor, Pruebe esto.

ExecutorService exec= Executors.newCachedThreadPool() 
for (String name : fileNames){ 
exec.submit(new Runnable() 
{ 
    public void run() 
    { 
    downloadFile(name, toPath); 
    } 
}); 
} 

Si quiere decir tres de descarga en ejecución al mismo tiempo, puede utilizar:

Executors.newFixedThreadPool(3) 
+0

Ahora bloquea while 'execute()' ing the 'Runnable', quería llamar a' exec.submit() ':) –

+0

@Philipp Reichart ¿realmente sabe de lo que está hablando? ¿Qué bloques mientras se ejecuta? Escucha bruv! evite marcar a las personas cuando no sabe de qué se trata. – Bitmap

+0

Sí, lo hago, en realidad esta vez me ha mordido. ['Execute.execute()'] (http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/Executor.html#execute (java.lang.Runnable)) puede "... ejecutar en un nuevo hilo, en un hilo agrupado, o ** en el hilo de llamada **, a discreción de la implementación Ejecutor."Realmente desea declarar la variable como' ExecutorService' y usar ['submit()'] (http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html# submit (java.lang.Runnable)). –

0

Todo el enfoque mencionado anteriormente crea subprocesos, pero el Concurreny real no se logra.

ExecutorService pool = Executors.newFixedThreadPool(5); 
final File folder = new File("YOUR_FILES_PATH"); 
int l = folder.listFiles().length; 
System.out.println("Total Files----"+folder.listFiles().length); 
long timeStartFuture = Calendar.getInstance().getTimeInMillis(); 
    pool.execute(new DownloadFile(folder,0,l/2)); 
    pool.execute(new DownloadFile(folder,(l/2),l)); 
    pool.shutdown(); 
    try { 
     pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    long timeEndFuture = Calendar.getInstance().getTimeInMillis(); 
    long timeNeededFuture = timeEndFuture - timeStartFuture; 
    System.out.println("Parallel calculated in " + timeNeededFuture + " ms"); 

El programa anterior se utiliza para lograr concurreny y modifique según sus necesidades.

Cuestiones relacionadas