Является ли писатель атомным методом? - PullRequest
6 голосов
/ 01 марта 2012

Я хочу записать несколько строк в файл. Итак, я использовал BufferedWriter класс. Поскольку многие потоки записывают в этот файл, я хочу знать, являются ли методы write и writeLine атомарными или нет.

Кроме того, я хочу, чтобы программа записывала вывод в несколько файлов и по 100 строк на файл (например, file.txt0, file.txt1, ...). Например

public class Main {
    static ExecutorService exec = Executors.newFixedThreadPool(5);
    BufferedWriter bw;
    public class myWriter implements Runnable {
        String str;
        myWriter (String str) {
            this.str = str;
        }
        public void run() {
            bw.write(str);
            bw.writeLine();
        }
    }
    public static void main(String[] args) {
        bw = new BufferedWriter(new  FileWriter("train.txt"));
        for (String arg: args)
            exec.execute(new myWriter(arg));
        exec.awaitTermination(100000, TimeUnit.MILLISECONDS);
    }
}

Может ли кто-нибудь мне помочь? Если они не атомарны, как я могу сделать их атомарными и избежать столкновения?

Ответы [ 5 ]

6 голосов
/ 01 марта 2012

Нет, это не атомные.

Если вы хотите многократную запись в один и тот же файл, используйте FileLocks .

try {
    // Get a file channel for the file
    File file = new File("filename");
    FileChannel channel = new RandomAccessFile(file, "rw").getChannel();

    // Use the file channel to create a lock on the file.
    // This method blocks until it can retrieve the lock.
    FileLock lock = channel.lock();

    // Try acquiring the lock without blocking. This method returns
    // null or throws an exception if the file is already locked.
    try {
        lock = channel.tryLock();
    } catch (OverlappingFileLockException e) {
        // File is already locked in this thread or virtual machine
    }

    // Release the lock
    lock.release();

    // Close the file
    channel.close();
} catch (Exception e) {
}
5 голосов
/ 02 июля 2012

Код ниже является исходным кодом из jdk6, это реализация записи в BufferedWriter, потому что в теле функции есть synchronized, я думаю, что write() в BufferedWriter является потокобезопасным.Кстати, write(String) реализуется путем вызова write(String,int,int).

public void write(String s, int off, int len) throws IOException {

    synchronized (lock) {

        ensureOpen();

        int b = off, t = off + len;

        while (b < t) {

            int d = min(nChars - nextChar, t - b);
            s.getChars(b, b + d, cb, nextChar);
            b += d;
            nextChar += d;

            if (nextChar >= nChars)
                flushBuffer();
            }
        }
    }
}
3 голосов
/ 01 марта 2012

Вы можете использовать FileLocks, но это может быть дорого.

Лично я бы использовал обычную объектную блокировку.например,

synchronized(bufferedWriter) {
  bufferedWriter.write stuff
  bufferedWriter.write more stuff
}
1 голос
/ 27 сентября 2017

Да, BufferedWriter является потокобезопасным.Смотрите фрагмент ниже.При записи контента синхронизированный блок обеспечивает безопасность потока.

public void write(int c) throws IOException {
    synchronized (lock) {
        ensureOpen();
        if (nextChar >= nChars)
            flushBuffer();
        cb[nextChar++] = (char) c;
    }
}

введите описание изображения здесь

1 голос
/ 27 марта 2013

NGloom прав, ниже приведен дамп потока части программы, которая осуществляет параллельный доступ к методу BufferredWriter.append() (среда выполнения Oracle JDK 7), который вообще не использует синхронизацию в теле метода. Совершенно очевидно, что реализация BufferredWriter.append() использует монитор на экземпляре объекта BufferredWriter, поэтому он является поточно-ориентированным. Однако я не могу найти что-либо о безопасности потоков в соответствующем документе Java , и поэтому API не дает никаких таких гарантий, так как такие реализации могут отличаться? Кроме того, тот факт, что Writer.write() является потокобезопасным, не мешает другому устройству записи, которое оборачивает другой объект OutputStream в тот же файл, пытаться выполнять одновременную запись в него, что не безопасно.

ForkJoinPool-1-worker-3" daemon prio=10 tid=0x00007f358c002800 nid=0x3e66 waiting for monitor entry [0x00007f360bdfb000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.io.BufferedWriter.write(BufferedWriter.java:220)
    - waiting to lock <0x0000000760da06d8> (a java.io.OutputStreamWriter)
    at java.io.Writer.write(Writer.java:157)
    at java.io.Writer.append(Writer.java:227)
    at ...


ForkJoinPool-1-worker-2" daemon prio=10 tid=0x00007f358c001000 nid=0x3e65 waiting for monitor entry [0x00007f360befc000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.io.BufferedWriter.write(BufferedWriter.java:220)
    - waiting to lock <0x0000000760da06d8> (a java.io.OutputStreamWriter)
    at java.io.Writer.write(Writer.java:157)
    at java.io.Writer.append(Writer.java:227)
    at ...
...