2011-09-21 120 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