2012-03-01 5 views
6

일부 문자열을 파일에 쓰려고합니다. 그래서 BufferedWriter 클래스를 사용했습니다. 많은 쓰레드가 그 파일에 쓰는 경향이 있기 때문에, writeLake의 메소드가 원자인지 아닌지를 알고 싶습니다.작가는 원자 적 방법입니까?

또한이 프로그램은 출력을 여러 파일과 파일 당 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); 
    } 
} 

나를 도와 줄 수 있습니까? 만약 그들이 원자가 아니라면 어떻게 원자를 만들고 충돌을 피할 수 있습니까?

답변

6

아니요. 원자가 아닙니다.

동일한 파일에 여러 개의 쓰기를 사용하려면 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) { 
} 
+2

+1

public void write(int c) throws IOException { synchronized (lock) { ensureOpen(); if (nextChar >= nChars) flushBuffer(); cb[nextChar++] = (char) c; } } 
. 알아 둘만한. – Mudassir

+0

멋진 작품. 출력을 여러 파일 (파일 당 100 줄)에 쓰려면 어떻게해야합니까? – orezvani

+0

@emab에 따라 다릅니다. (정확하게) 무엇을하고 싶은지에 대한 자세한 내용으로 질문을 편집해야합니다. ( – Marcelo

3

FileLocks를 사용할 수는 있지만 비용이 많이 듭니다.

개인적으로는 일반적인 개체 잠금을 사용합니다. 예 :

synchronized(bufferedWriter) { 
    bufferedWriter.write stuff 
    bufferedWriter.write more stuff 
} 
+0

하지만 여기에서는 bufferedWriter가 final이어야합니다. 내 bufferedWriter는 최종 결과가 아닙니다. 출력이 100 라인마다 새 파일이 열리기 때문입니다 – orezvani

+0

이 경우에는 사용할 수있는 'final'인 객체가 필요합니다. –

5

아래의 코드는 내가 BufferedWriterwrite()는 스레드로부터 안전하다고 생각, 함수 본문에 synchronized이의 원인이 BufferedWriter에서 쓰기의 구현이다, JDK6에서 소스 코드입니다. Btw, 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(); 
      } 
     } 
    } 
} 
+0

그것은 각 쓰기 원자를 만들지 만,'bw.write (str); bw.writeLine();'을 호출 할 때 OP의 코드는 여전히 동시성 문제를 가지고있다. – assylias

+0

@assylias 그게 유일한 문제는 아니며 flushToBuffer가 파일에 쓰는 것을 끝내게됩니다. 따라서 동시 스레드가 파일을 읽는 경우 부분 데이터를 읽을 수 있습니다. – user1706991

1

NGloom은 오른쪽 인 방법 본체에 어떠한 동기화 해를 사용하지 BufferredWriter.append() 방법 (오라클 JDK 7 런타임)에 동시 액세스를 수행하는 프로그램의 일부 쓰레드 덤프입니다 다음. BufferredWriter.append()의 구현은 BufferredWriter 객체의 인스턴스에서 모니터를 사용하므로 스레드로부터 안전합니다. 그러나 나는 스레드 안전성에 대해 아무것도 찾을 수 없다. 따라서 그러한 구현은 다양 할 수 있기 때문에 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 ... 
1

예, BufferedWriter는 스레드로부터 안전합니다. 아래 스 니펫을 참조하십시오. 콘텐츠 동기화 블록을 쓰는 동안 스레드 안전을 보장합니다.

enter image description here

관련 문제