#java #multithreading #file #thread-safety
#java #многопоточность #файл #потокобезопасность
Вопрос:
Все, я пытаюсь прочитать файл, который будет записан несколькими потоками, я собираюсь использовать BufferedReader
для чтения этого файла в потоке.
Код выглядит следующим образом.
FileReader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader);
String detail;
while ((detail =br.readLine()) != null)
{
...
}
В настоящее время, похоже, работает нормально. Но у меня есть несколько вопросов по этому поводу.
Если вопрос звучит глупо. пожалуйста, не смейтесь надо мной. Спасибо.
Возможно ли, что цикл никогда не прерывался? потому что другие потоки записывают в файл.Так что, возможно, readLine()
может никогда не возвращать значение null?
Обновлено
Допустим, есть 3 потока (T1, T2, T3).
T1 и T2 являются записывающими.
T3 — это reader.
Код выполняется в следующей последовательности.
1. Номер текущей строки файла равен 100.
2.T1 записать строку в файл.(количество строк файла увеличивается до 101)
3.T3 считывает последнюю строку файла (101). следующее чтение получит значение null.
4.T2 добавьте строку в файл.(количество строк файла увеличивается до 102)
5.T3 прочитайте еще раз….(Возвращает ли он значение null или нет? потому что T2 просто добавил новую строку в файл перед повторным чтением T3.)
Пожалуйста, помогите просмотреть его. заранее спасибо.
Комментарии:
1. Если считыватель читает быстрее, чем записывающие устройства, в конечном итоге он дойдет до конца файла, а затем вернет значение null. Если нет, то это завершится, когда в вашей файловой системе закончится свободное место, и записи прекратятся с помощью исключения IOException
2. @Pablo Я просто не уверен, может ли произойти то, о чем я сказал. Это похоже на проблему гонки? Спасибо
3. Для имитации сценария вы можете установить приоритет потока или время ожидания
4. Все ли эти потоки находятся в одной JVM? Если это так, зачем использовать неуклюжий и подверженный ошибкам подход к файлу вместо чего-то вроде параллельной очереди?
5. Кажется, было бы проще написать свою собственную реализацию регистратора.
Ответ №1:
Да, возможно, что цикл никогда не закончится (по крайней мере, пока у вас не закончится память). Вот некоторый код, подтверждающий это:
public class test {
public static void main(String[] args) {
// start thread to write to file
new Thread(new Runnable() {
@Override
public void run() {
FileWriter writer;
try {
int i = 1;
writer = new FileWriter("D:\text.txt");
writer.append("line" i "n");
writer.flush();
while (true)
{
writer.append("line" i "n");
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// start thread to read file
new Thread(new Runnable() {
@Override
public void run() {
try {
FileReader reader = new FileReader("D:\text.txt");
BufferedReader br = new BufferedReader(reader);
String detail;
while ((detail =br.readLine()) != null)
{
System.out.println(detail);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
Комментарии:
1. Верно, я также провел несколько тестов, как и вы. Это может произойти. (никогда не заканчивается.)
Ответ №2:
Я провел для этого некоторый эксперимент.
Один eclipse запускает программу как writer .
public class Main {
private static Logger log = Logger.getLogger(Main.class);
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
PropertyConfigurator.configure("log4j.properties");
log.warn("Test test test ");
}
}
Другой eclipse запускает программу как reader.
public class Main {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StringBuffer intiLine = new StringBuffer("");
FileReader reader = new FileReader("D:\logs\notify-subscription.log");
BufferedReader br = new BufferedReader(reader);
String detail;
while ((detail =br.readLine()) != null)//debug and set breakpoint here
{
System.out.println(detail);
}
}
}
прежде чем я начал их тестировать. Исходное содержимое файла журнала пустое.
Сначала я запустил программу чтения. результат br.readLine()
должен быть нулевым. Но я установил точку останова в строке кода while ((detail =br.readLine()) != null)
run, перед ее запуском я запустил программу записи. Итак, файл содержит test test test
. и br.readLine()
не будет нулевым.
Ответ №3:
Вы абсолютно правы.Также существует вероятность взаимоблокировки, если вы продолжаете создавать потоки для записи содержимого в файл.Поскольку, если потоки продолжают записывать в файл, не будет никаких шансов выйти из цикла, он переходит в бесконечное состояние
Комментарии:
1. Но дисковое пространство не бесконечно, авторы не могут писать вечно
2. Бесконечный цикл не является тупиковой ситуацией.
3. ДА. вы правы. Но я считаю, что это может повлиять на сценарии ожидания запроса @Pablo