1 /*
   2  * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug 5073414
  27  * @summary Ensure that there is no race condition in BufferedReader.readLine()
  28  *          when a line is terminated by '\r\n' is read by multiple threads.
  29  */
  30 
  31 import java.io.*;
  32 import java.util.concurrent.TimeUnit;
  33 import java.util.concurrent.ExecutorService;
  34 import java.util.concurrent.Executors;
  35 
  36 public class ReadLineSync {
  37 
  38     public static int lineCount = 0;
  39 
  40     public static void main( String[] args ) throws Exception {
  41 
  42         String dir = System.getProperty(".", ".");
  43         File f = new File(dir, "test.txt");
  44         createFile(f);
  45         f.deleteOnExit();
  46 
  47         BufferedReader reader = new BufferedReader(
  48                                 new FileReader(f));
  49         try {
  50             int threadCount = 2;
  51 
  52             ExecutorService es = Executors.newFixedThreadPool(threadCount);
  53 
  54             for (int i=0; i < threadCount; i++)
  55                 es.execute(new BufferedReaderConsumer(reader));
  56 
  57             // Wait for the tasks to complete
  58             es.shutdown();
  59             while (!es.awaitTermination(60, TimeUnit.SECONDS));
  60         } finally {
  61             reader.close();
  62         }
  63     }
  64 
  65     static class BufferedReaderConsumer extends Thread {
  66         BufferedReader reader;
  67 
  68         public BufferedReaderConsumer( BufferedReader reader ) {
  69             this.reader = reader;
  70         }
  71 
  72         public void run() {
  73             try {
  74                 String record = reader.readLine();
  75 
  76                 if ( record == null ) {
  77                     // if the first thread is too fast the second will hit
  78                     // this which is ok
  79                     System.out.println( "File already finished" );
  80                     return;
  81                 }
  82 
  83                 if ( record.length() == 0 ) {
  84                     // usually it comes out here indicating the first read
  85                     // done by the second thread to run failed
  86                     System.out.println("Empty string on first read." +
  87                                 Thread.currentThread().getName() );
  88                 }
  89 
  90                 while ( record != null ) {
  91                     lineCount++;
  92 
  93                     // Verify the token count
  94                     if ( record.length() == 0 ) {
  95                         // very occasionally it will fall over here
  96                         throw new Exception( "Invalid tokens with string '" +
  97                                 record + "' on line " + lineCount );
  98                     }
  99                     record = reader.readLine();
 100                 }
 101             }
 102             catch ( Exception e ) {
 103                 e.printStackTrace();
 104             }
 105         }
 106     }
 107 
 108 
 109     // Create a relatively big file
 110 
 111     private static void createFile(File f) throws IOException {
 112         BufferedWriter w = new BufferedWriter(
 113                            new FileWriter(f));
 114         int count = 10000;
 115         while (count > 0) {
 116 
 117             w.write("abcd \r\n");
 118             w.write("efg \r\n");
 119             w.write("hijk \r\n");
 120             w.write("lmnop \r\n");
 121             w.write("qrstuv \r\n");
 122             w.write("wxy and z \r\n");
 123             w.write("now you \r\n");
 124             w.write("know your \r\n");
 125             w.write("abc \r\n");
 126             w.write("next time \r\n");
 127             w.write("want you \r\n");
 128             w.write("sing with me \r\n");
 129 
 130             count--;
 131         }
 132         w.close();
 133     }
 134 }