<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 22, 文章 - 0, 評論 - 1, 引用 - 0
    數據加載中……

    java中Writer的線程安全性

    以前負責一個項目,我負責從一個超大的文本文件中讀取信息存入數據庫再進一步分析。而文本文件內容是每行一個json串。我在解析的過程中發現,有很小的概率json串的結構會破壞,比如前一個json串只寫了半行,后面就被另一個json串覆蓋掉了。
    與產生日志的部門溝通,他們說是多線程使用log4j寫入,可能偶爾會有串行。
    具體他們是否使用log4j的AsyncAppender我不太了解,暫時也沒去看log4j的源碼,當時只是簡單的忽略異常的行了事兒。
    現在比較閑,想測試一下jdk里面各種輸出方式,例如Writer,在多線程交替寫入文件一行時是否會出現串行的情況,于是便出現了本文。
    測試分兩部分:
    1,多個線程各自開啟一個FileWriter寫入同一個文件。
    2,多個線程共用一個FileWriter寫入同一個文件。
    --------------------------------------------------
    首先來看FileWriter的JDK說明:
    “某些平臺一次只允許一個 FileWriter(或其他文件寫入對象)打開文件進行寫入”——如果是這樣,那么第1個測試便不用做了,可事實上至少在windows下并非如此。
    上代碼(別嫌丑,咱是在IO,不是在測多線程,您說是吧?):
    1,多個線程各自開啟一個FileWriter寫入同一個文件。
     1     //在100毫秒的時間內,10個線程各自開一個FileWriter,
     2     //同時向同一個文件寫入字符串,每個線程每次寫一行。
     3     //測試結果:文件內容出現混亂,串行
     4     private void multiThreadWriteFile() throws IOException{
     5         File file=new File(basePath+jumpPath+fileName);
     6         file.createNewFile();
     7         
     8         //創建10個線程
     9         int totalThreads=10;
    10         WriteFileThread[] threads=new WriteFileThread[totalThreads];
    11         for(int i=0;i<totalThreads;i++){
    12             WriteFileThread thread=new WriteFileThread(file,i);
    13             threads[i]=thread;
    14         }
    15         
    16         //啟動10個線程
    17         for(Thread thread: threads){
    18             thread.start();
    19         }
    20         
    21         //主線程休眠100毫秒
    22         try {
    23             Thread.sleep(100);
    24         } catch (InterruptedException e) {
    25             e.printStackTrace();
    26         }
    27         
    28         //所有線程停止
    29         for(WriteFileThread thread: threads){
    30             thread.setToStop();
    31         }
    32         System.out.println("還楞著干什么,去看一下文件結構正確與否啊!");
    33     }

     1     class WriteFileThread extends Thread{
     2         private boolean toStop=false;
     3         private FileWriter writer;
     4         private int threadNum;
     5         private String lineSeparator;
     6         
     7         WriteFileThread(File file,int threadNum) throws IOException{
     8             lineSeparator=System.getProperty("line.separator");
     9             writer=new FileWriter(file,true);
    10             this.threadNum=threadNum;
    11         }
    12         
    13         @Override
    14         public void run() {
    15             while(!toStop){
    16                 try {
    17                     writer.append("線程"+threadNum+"正在寫入文件," +
    18                             "媽媽說名字要很長才能夠測試出這幾個線程有沒有沖突啊," +
    19                             "不過還是沒有論壇里帖子的名字長,怎么辦呢?" +
    20                             "哎呀,后面是換行符了"+lineSeparator);
    21                     
    22                 } catch (IOException e) {
    23                     e.printStackTrace();
    24                 }
    25             }
    26             System.out.println("---------線程"+threadNum+"停止執行了");
    27         }
    28 
    29         public void setToStop() {
    30             this.toStop = true;
    31         }
    32     }
    測試結果:
    產生5MB左右的文本文件,里面出現大約5%的文本串行現象。
    --------------------------------------------------
    接下來我們看多個線程共用一個FileWriter寫入同一個文件的情況:
    在Writer抽象類里面有一個protected類型的lock屬性,是一個簡單Object對象。
    JDK里對這個lock屬性的描述如下:“用于同步針對此流的操作的對象。為了提高效率,字符流對象可以使用其自身以外的對象來保護關鍵部分。因此,子類應使用此字段中的對象,而不是 this 或者同步的方法。 ”——看來,多線程共用同一個writer的方案有戲。
    繼續看下源代碼,從FileWriter的writer方法開始看起,調用過程如下:
    FileWriter->OutputStreamWriter.write->StreamEncoder.write
    其中StreamEncoder.write的源碼如下:
    (JDK自帶源碼不包括StreamExcoder,可以在這里查看 http://www.docjar.com/html/api/sun/nio/cs/StreamEncoder.java.html)
     1 public void write(char cbuf[], int off, int len) throws IOException {
     2     synchronized (lock) {
     3         ensureOpen();
     4         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
     5                 ((off + len) > cbuf.length) || ((off + len) < 0)) 
     6             {
     7                 throw new IndexOutOfBoundsException();
     8             } else if (len == 0) {
     9                 return;
    10             }
    11         implWrite(cbuf, off, len);
    12     }
    13 }
    可以看到FileWriter在寫入時,同步在了對應的FileOutputStream對象上——依此分析,多個線程共用一個FileWriter寫入同一個文件,一次一行的情況下,不會出現串行。
    寫代碼測試一下:
     1     //多線程爭搶寫入同一個文件的測試,一次一行
     2     //多個線程公用一個FileWriter
     3     //測試結果:
     4     private void multiThreadWriteFile2() throws IOException{
     5         File file=new File(basePath+jumpPath+fileName);
     6         file.createNewFile();
     7         FileWriter fw=new FileWriter(file);
     8         
     9         //創建10個線程
    10         int totalThreads=10;
    11         WriteFileThread2[] threads=new WriteFileThread2[totalThreads];
    12         for(int i=0;i<totalThreads;i++){
    13             WriteFileThread2 thread=new WriteFileThread2(fw,i);
    14             threads[i]=thread;
    15         }
    16         
    17         //啟動10個線程
    18         for(Thread thread: threads){
    19             thread.start();
    20         }
    21         
    22         //主線程休眠100毫秒
    23         try {
    24             Thread.sleep(100);
    25         } catch (InterruptedException e) {
    26             e.printStackTrace();
    27         }
    28         
    29         //所有線程停止
    30         for(WriteFileThread2 thread: threads){
    31             thread.setToStop();
    32         }
    33         System.out.println("還楞著干什么,去看一下文件結構正確與否啊!");
    34     }

     1     class WriteFileThread2 extends Thread{
     2         private boolean toStop=false;
     3         private FileWriter writer;
     4         private int threadNum;
     5         private String lineSeparator;
     6         
     7         WriteFileThread2(FileWriter writer,int threadNum){
     8             lineSeparator=System.getProperty("line.separator");
     9             this.writer=writer;
    10             this.threadNum=threadNum;
    11         }
    12         
    13         @Override
    14         public void run() {
    15             while(!toStop){
    16                 try {
    17                     writer.append("線程"+threadNum+"正在寫入文件," +
    18                             "媽媽說名字要很長才能夠測試出這幾個線程有沒有沖突啊," +
    19                             "不過還是沒有論壇里帖子的名字長,怎么辦呢?" +
    20                             "哎呀,后面是換行符了"+lineSeparator);
    21                 } catch (IOException e) {
    22                     e.printStackTrace();
    23                 }
    24             }
    25             System.out.println("---------線程"+threadNum+"停止執行了");
    26         }
    27 
    28         public void setToStop() {
    29             this.toStop = true;
    30         }
    31     }
    測試結果:
    產生2.2MB左右的文本文件,里面沒有出現任何串行現象。
    --------------------------------------------------
    那么BufferedWriter又如何呢?
    按道理BufferedWriter只是把別的Writer裝飾了一下,在底層寫的時候也是同步的。
    看源碼:
    1     void flushBuffer() throws IOException {
    2         synchronized (lock) {
    3             ensureOpen();
    4             if (nextChar == 0)
    5                 return;
    6             out.write(cb, 0, nextChar);
    7             nextChar = 0;
    8         }
    9     }
    BufferedWriter.write和BufferedWriter.flushBuffer的方法同步在了被包裝的Writer這個對象上。
    也就是說,BufferedWriter.write和BufferedWriter.flushBuffer都有同步塊包圍,說明按上述環境測試時,是不會出現串行現象的。
    --------------------------------------------------
    最終結果:
    1,windows下,可以開多個線程操作多個FileWriter寫入同一個文件,多個FileWriter切換時,會導致相互交錯,破壞字符串結構的完整性。
    2,多個線程操作FileWriter或者BufferedWriter時,每一次寫入操作都是可以保證原子性的,也即:FileWriter或者BufferedWriter是線程安全的——呃,這個結論貌似好簡單啊,JDK文檔里有說明嗎?沒看到啊。
    3,由于第2條中的線程安全,寫入速度下降超過一半。

    posted on 2012-09-02 00:13 王星游 閱讀(3373) 評論(0)  編輯  收藏 所屬分類: java

    主站蜘蛛池模板: 青青草无码免费一二三区| caoporm碰最新免费公开视频| a级毛片在线视频免费观看| 免费在线观看亚洲| 国产AV无码专区亚洲AV蜜芽 | 亚洲中文字幕AV每天更新| 猫咪免费人成网站在线观看| 亚洲av福利无码无一区二区| 99视频在线免费观看| 亚洲AV无码久久精品成人| 日本视频在线观看永久免费| 亚洲国产精品久久久久婷婷软件 | 成年女人视频网站免费m | 青娱乐在线视频免费观看| 免费在线观看日韩| 插鸡网站在线播放免费观看| 久久亚洲色一区二区三区| 嫩草在线视频www免费看| 亚洲美女激情视频| 亚洲人成网站免费播放| 亚洲人成色777777精品| 亚洲AV无码乱码在线观看性色扶| 成人国产精品免费视频| 中文字幕亚洲综合精品一区| 黄色成人网站免费无码av| 国产成人亚洲精品电影| 亚洲毛片αv无线播放一区| 无码午夜成人1000部免费视频| 亚洲av无码电影网| 国产精品免费小视频| 美女被免费网站91色| 亚洲精彩视频在线观看| 免费无码一区二区三区蜜桃大| 一区免费在线观看| 亚洲午夜精品久久久久久人妖| 97无码免费人妻超级碰碰碰碰 | 免费v片视频在线观看视频| 国产日韩精品无码区免费专区国产| 亚洲第一中文字幕| 日本黄色免费观看| 日韩人妻无码精品久久免费一|