2012-04-05 2 views
1

У меня 20 потоков, которые пишут с помощью функции println() в файле с именем results.txt. Как я могу синхронизировать их все?Запись в текстовый файл из нескольких потоков?

Я отмечаю каждый раз, когда запускается моя программа, у меня есть разное количество строк текста в файле результатов. Txt.

спасибо.

+13

просто интересно, вы получили такое же домашнее задание? http://stackoverflow.com/questions/9972549/threads-and-file-writing –

+1

20 нитей .. 20 нитей .. каковы шансы? –

+0

различный количество линий .. другой количество линий .. –

ответ

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 *» должен быть «объектом *» (созданным из класса с указанными синхронизированными методами), поскольку методы 'synchronized' являются только взаимно исключающими для каждого объекта. –

+0

, поэтому мне нужно написать класс «I/O» и вызвать его в коде как объект для печати? –

+1

@MarcoMicheli Ключевой момент в этом ответе: ['synchronized'] (http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) –

-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

Из FileDock's JavaDoc: «Файловые блокировки хранятся от имени всей виртуальной машины Java. Они не подходят для управления доступом к файлу несколькими потоками на той же виртуальной машине». – theadam

+0

@theadam - за этой цитатой немедленно следует * Объекты блокировки файлов безопасны для использования несколькими параллельными потоками.* - просто говоря – OldCurmudgeon

+0

Несколько потоков могут безопасно использовать полученный объект FileLock, однако эта блокировка НЕ ​​подходит для управления доступом к файлу несколькими потоками. То есть - сам объект (FileLock) является потокобезопасным. Он не должен использоваться, как вы его описываете. – theadam

Смежные вопросы