2012-04-05 68 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