zoukankan      html  css  js  c++  java
  • 关于Java OutputStream 线程安全问题

    今天偶尔发现java的输出流的线程安全问题

    先看代码吧

     

    1. import java.io.File;  
    2. import java.io.FileInputStream;  
    3. import java.io.FileOutputStream;  
    4. import java.io.OutputStream;  
    5. import java.util.Random;  
    6. import java.util.concurrent.TimeUnit;  
    7.   
    8.   
    9. public class TestFileWrite {  
    10.   
    11.     public static void main(String[] args)throws Exception {  
    12.         // TODO Auto-generated method stub  
    13.         File f = new File("a"+System.currentTimeMillis());  
    14.         f.createNewFile();  
    15.         java.util.concurrent.CountDownLatch cwl = new java.util.concurrent.CountDownLatch(2);  
    16.         FileOutputStream fos = new FileOutputStream(f);  
    17.         new Thread(new WriteThread(cwl,fos,"bb")).start();  
    18.         new Thread(new WriteThread(cwl,fos,"aaasdfasfd")).start();  
    19.         cwl.countDown();  
    20.         cwl.countDown();  
    21.         TimeUnit.SECONDS.sleep(1);  
    22.         fos.flush();  
    23.         FileInputStream f1 = new FileInputStream(f);  
    24.         byte[] bytearray = new byte[1024];  
    25.         int n = f1.read(bytearray);  
    26.         f1.close();  
    27.         System.out.println(new String(bytearray,0,n));  
    28.     }  
    29.   
    30. }  
    31.   
    32. class WriteThread implements Runnable{  
    33.   
    34.     OutputStream os = null;  
    35.     String fSpe = null;  
    36.     java.util.concurrent.CountDownLatch cwl;  
    37.     public WriteThread(java.util.concurrent.CountDownLatch cwl,OutputStream os, String fSpe) {  
    38.         super();  
    39.         this.cwl = cwl;  
    40.         this.os = os;  
    41.         this.fSpe = fSpe;  
    42.     }  
    43.   
    44.   
    45.     @Override  
    46.     public void run() {  
    47. //      for(int i=0;i<10;i++)  
    48. //      {  
    49.             try {  
    50.                 cwl.await();  
    51.                 os.write((fSpe+" ").getBytes());  
    52. //              TimeUnit.SECONDS.sleep(new Random().nextInt(10));  
    53.             } catch (Exception e) {  
    54.                 // TODO Auto-generated catch block  
    55.                 e.printStackTrace();  
    56.             }  
    57. //      }  
    58.           
    59.     }  
    60. }  

    这里的输出结果很有意思,会相互覆盖,偶尔输出

     

    aaasdfasfd

    有时候输出

    bb
    dfasfd

    输出第二种是因为第一bb 把第一个字符串给覆盖掉了

    观察Filetputtream的代码,发现很有意思,整个类是非线程安全的,不过在类的注释上没有标记这一点,最底层的写入是调用本地方法

     

    1. private native void writeBytes(byte b[], int off, int len, boolean append)  


    此处的相互覆盖应该是底层没有对并发进行处理,导致两重生之大文豪个线程同时在字节流的同一位置进行写入,应该还会有更奇怪的输出

     

    ab

    dfasfd

    不过这种输出的重现几率很小,理论上应该存在

     

    再观察DataOutputStream 发现只有write(byte b[])会加锁,其他时候不会加锁,不知到为何,难道是为了提升性能故意把锁去掉了?

  • 相关阅读:
    JavaScript和DOM
    CSS补充以及后台页面布局
    HTML标签和CSS基础
    基于SQLAlchemy实现的堡垒机
    PymySQL
    SQLAlchemy
    负数取模
    list
    算法(3)
    python初识(3)
  • 原文地址:https://www.cnblogs.com/jiangye/p/3508928.html
Copyright © 2011-2022 走看看