2012-04-05 80 views
1

我有20個線程使用println()函數在名爲results.txt的文件上寫入。我如何同步它們?從多個線程寫入文本文件?

我注意到每次我的程序運行時,我在results.txt中都有不同數量的文本行。

謝謝。

+13

只是想知道,你得到了同樣的作業嗎? http://stackoverflow.com/questions/9972549/threads-and-file-writing – 2012-04-05 11:10:03

+1

20個線程.. 20個線程..有什麼機會? – 2012-04-05 12:01:53

+0

不同行數..不同行數.. – 2012-04-05 12:03:31

回答

17

通過包含synchronized method的類訪問文件以寫入文件。一次只有一個線程將能夠執行該方法。

我認爲Singleton模式會適合您的問題:

package com.test.singleton; 

public class Singleton { 
    private static final Singleton inst= new Singleton(); 

    private Singleton() { 
     super(); 
    } 

    public synchronized void writeToFile(String str) { 
     // Do whatever 
    } 

    public Singleton getInstance() { 
     return inst; 
    } 

} 

每當你需要編寫你的文件的時候,你只將不得不撥打:

Singleton.getInstance().writeToFile("Hello!!"); 
+1

+1簡單但有效。然而,「a * class *」應該是「an * object *」(由具有所述同步方法的類實例化),因爲'synchronized'方法只是相互排斥的每個對象。 – 2012-04-05 10:47:30

+0

所以我必須編寫一個「I/O」類,並在代碼中調用它來打印對象? – 2012-04-05 10:48:59

+1

@MarcoMicheli這個答案的關鍵點是:['synchronized'](http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) – 2012-04-05 10:49:30

-1

使用日誌框架如具有所有已經解決的logback。

0

您打算將數據寫入一個文件。所以如果你試圖鎖定整個文件,最好使用一個線程來完成這項工作。雖然你產生了20個線程,但每次調用方法時只有其中一個線程正在運行,其他線程只是在等待鎖定。

我建議您使用RandomAccessFile將數據寫入文件。然後每個線程都可以將一些獨特的數據寫入文件而不鎖定整個文件。

一些演示代碼如下

try { 
    final RandomAccessFile file = new RandomAccessFile("/path/to/your/result.txt", "rw"); 
    final int numberOfThread = 20; 
    final int bufferSize = 512; 
    ExecutorService pool = Executors.newFixedThreadPool(numberOfThread); 
    final AtomicInteger byteCounter = new AtomicInteger(0); 
    final byte[] yourText = "Your data".getBytes(); 
    for (int i = 0; i < yourText.length; i++) { 
     pool.submit(new Runnable() { 
      @Override 
      public void run() { 
       int start = byteCounter.getAndAdd(bufferSize); 
       int chunkSize = bufferSize; 
       if (start + bufferSize > yourText.length) { 
        chunkSize = yourText.length - start; 
       } 
       byte[] chunkData = new byte[chunkSize]; 
       System.arraycopy(yourText, start, chunkData, 0, chunkSize); 
       try { 
        file.write(chunkData); 
       } catch (IOException e) { 
        //exception handle 
       } 
      } 
     }); 
    } 
    file.close(); 
} catch (Exception e) { 
    //clean up 
} 
4

重複的問題......複製答案。 As I said here:

如果你可以拿着你的文件作爲FileOutputStream你可以這樣鎖定:

FileOutputStream file = ... 
.... 
// Thread safe version. 
void write(byte[] bytes) { 
    try { 
    boolean written = false; 
    do { 
     try { 
     // Lock it! 
     FileLock lock = file.getChannel().lock(); 
     try { 
      // Write the bytes. 
      file.write(bytes); 
      written = true; 
     } finally { 
      // Release the lock. 
      lock.release(); 
     } 
     } catch (OverlappingFileLockException ofle) { 
     try { 
      // Wait a bit 
      Thread.sleep(0); 
     } catch (InterruptedException ex) { 
      throw new InterruptedIOException ("Interrupted waiting for a file lock."); 
     } 
     } 
    } while (!written); 
    } catch (IOException ex) { 
    log.warn("Failed to lock " + fileName, ex); 
    } 
} 
+0

來自FileLock的JavaDoc: 「代表整個Java虛擬機保留文件鎖定,它們不適用於控制同一虛擬機中多個線程對文件的訪問。 – theadam 2013-07-26 08:19:30

+0

@theadam - 緊隨其後的是*文件鎖對象可安全地用於多個併發線程。* - 只是說 – OldCurmudgeon 2013-07-26 08:35:54

+0

多個線程可以安全地使用獲得的FileLock對象,但是此鎖不適用於控制多線程對文件的訪問。那就是 - 對象(FileLock)本身是線程安全的。不應該像你描述的那樣使用它。 – theadam 2013-07-27 09:08:04