2011-09-21 117 views
2

这建立在我的previous question上。java线程从静态内部类访问外部类

我的ftp服务器有10个文件,比如test1.txt,test2.txt等等。我希望能够同时下载多个文件(最多3个)。我打电话downloadFilesByPattern(....)如果我不使用downloadFile()同步,那么只有一些文件不是全部​​下载。如果我使用同步,那么所有的文件都会下载,但我不认为它们并行发生。问题是因为实例变量被传递给所有线程,并且该实例上的方法被所有线程调用。

public class FTPClientService implements IClient { 

private String username; 
private String password; 
private String port; 
private String host; 
private String path; 
FTPClient client = new FTPClient(); 

private static class DownloadTask implements Runnable { 

    private String name; 
    private String toPath; 
    private IClient client; 

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

    @Override 
    public void run() { 
     System.out.println("download = " + name); 
     client.downloadFile(name, toPath); 
    } 
} 

public void downloadFilesByPattern(String fileNamePattern, final String outputFilePath) { 

    if(!changeDirectory()){ 
     return; 
    } 

    try { 
     //get a list of file names that match the pattern 
     String[] names = client.listNames(); 

     ExecutorService pool = Executors.newFixedThreadPool(3); 
     for (String name : names) { 
      //check if the filename matches the pattern 
      Pattern pattern = Pattern.compile(fileNamePattern); 
      Matcher matcher = pattern.matcher(name); 
      if(matcher.find()){ 
       System.out.println("Match found = " + name); 
       pool.submit(new DownloadTask(name, outputFilePath, this)); 
      }else{ 
       System.out.println("No match = " + name); 
      } 
     } 
     pool.shutdown(); 
     try { 
      pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
     } catch (InterruptedException ex) { 
     } 

    } catch (IOException ex) { 
    } 
} 

public synchronized void downloadFile(String fileName, String outputFilePath) { 

    FileOutputStream fos = null; 
    try { 
     fos = new FileOutputStream(outputFilePath+"/"+fileName); 
     if(this.isFilePresent(fileName)){ 
      //look for fileName in the path and write it to 
      client.retrieveFile(fileName, fos); 
      System.out.println("Downloading file " + fileName + " ..."); 
     }else{ 
      System.out.println("Could not find file " + fileName); 
     } 
    } catch (IOException ex) { 
    } finally { 
     try { 
      fos.close(); 
     } catch (IOException ex) { 
     } 
    } 
} 
} 

回答

4

这是因为它们都使用的

FTPClient client 

你需要或者创建FTPClientService的新实例每次下载/线程或具有FTPClient实例为每个线程相同的实例。我个人更喜欢使用ThreadLocal轻松实现的第二个变体。

0

FTPClient可能不是线程安全的(它来自哪种产品?)。如果您需要重新使用它,您可能需要在下载之前创建它,或创建一个FTP客户端池。

另外,我建议你修改你的命名约定,因为在代码ftpclient和你自己的客户端很难区分。

+0

谢谢你将改变名称 – user373201