с 5 попытки(( но сам решил, все забыл по потокам(( пришлось открывать лекцию с первого курса.
разбирать эту задачу нет особого смысла т.к она далека от реальности, просто хаотичное месиво из операторов видимо на запоминание, решили и пошли дальше не теряем время!
вообще хз. + вдруг reader.ready() выдаст true, а строка будет считана другим потоком и первый зависнет.
я сделала через
s = reader.readLine();
if (s != null)
пишем
когда if (s != null) = false поток сам завершиться
reader.ready() будет возвращать false до тех пор пока пользователь не введёт какие-то данные и не нажмёт enter ↵
После чего reader.ready() будет возвращать true до тех пор пока из буфера reader не будут вычитаны все данные и снова будет возвращать false пока не появятся новые данные т.е. пока пользователь снова не наберёт что-то и не нажмёт enter ↵
Предполагаю, что в данной задаче, если не проверять if (reader.ready()) { ... } то все потоки дойдут до reader.readLine() и будут стоять пока reader.readLine() не вернёт строку, а когда строка будет введена то один из потоков её получит, а остальные будут стоять дальше, пока не будет введена следующая строка. И тогда следующий поток получит строку и продолжит работу. В случае если после очередной строки в main()
(count > countReadStrings.get())
перестаёт быть true и у всех потоков вызывается interrupt() они продолжают тупо стоять в ожидании своей строки и только если ввести ещё 1-2 строки в консоли потоки наконец завершаются. Почему 1-2 почему не 3 (3 по-моему мне никогда вводить не приходилось) потому что метод reader.close() тоже блокирующий и в то время как потоки стоят на reader.readLine() ожидая ввода, main() стоит на строке reader.close() ожидая возможности закрыть уже этот Reader. И после ввода 1-2 строк как правило Reader закрывается и тот поток который стоял на
line = reader.readLine();
и который сможет продолжить после того как в main() отработал reader.close() словит исключение "java.io.IOException: Stream closed".
Я ещё использовал synchronize:
publicvoidrun(){//add your code here - добавьте код тутwhile(!isInterrupted()){synchronized(reader){try{if(reader.ready()){String line = reader.readLine();
result.add(line);
countReadStrings.incrementAndGet();}}catch(IOException e){//e.printStackTrace();}}}}
Пока я с этим разбирался обнаружил что в JDK есть исходники в архиве src.zipUPD: в IDEA просто Ctrl + B нажать когда курсор на имени класса или метода.
(до этого я гуглил и попадал на docjar или openjdk)
В моем случае он находится тут:
C:\Program Files\Java\jdk1.8.0_151\src.zip\java\io\Reader.java
C:\Program Files\Java\jdk1.8.0_151\src.zip\java\io\BufferedReader.java
Там можно посмотреть как устроены эти классы и что происходит при вызове методов ready() readLine() и close().
Ещё можно пользоваться дебаггером, но я пока не разобрался как дебажить многопоточные программы.
Конечный вариант который я написал бы сейчас
publicvoidrun(){//add your code here - добавьте код тутwhile(!isInterrupted()){// В блок synchronized нити входят по очередиsynchronized(reader){// Сразу проверяем а не прерван ли уже поток и если да - прерываем цикл.if(isInterrupted()){break;}try{// Только если в буфере есть данные.if(reader.ready()){String line = reader.readLine();
result.add(line);
countReadStrings.incrementAndGet();}}catch(IOException e){
e.printStackTrace();}}}}
но я не могу его проверить, валидатор даёт повторно решать задачи только в течение непродолжительного времени.
Если честно, то не совсем понятно зачем тут блок synchronized(если конечно reader не потоко безопасен), вот если бы он избавил код от проверки if (reader.ready()), тогда да, а так он кажется тут лишним, что он есть что его нет результат будет тот же.
Честно говоря я уже не помню точно почему я это написал.
Вроде бы получалось так что приходилось вводить больше строк чем надо, т.к. потоки застревали в ожидании ввода и не прерывались.
Сейчас проверил без synchronized - нормально все работает.
publicvoidrun(){try{while(!isInterrupted()){// Только если в буфере есть данные.if(reader.ready()){String line = reader.readLine();
result.add(line);
countReadStrings.incrementAndGet();}}}catch(IOException e){
e.printStackTrace();}}
Не помню с валидатором я боролся или с необходимостью вводить больше строк чем задано.
Но валидатор допиливают, это известное дело когда люди ругаются, что какой-то код не принимается, а потом он начинает приниматься валидатором.
Если прямо очень хочется докопаться до сути попробуй несколько раз позапускать и вводить
3
one
two
three
или
3
oneeeeeee
twoooooooo
threeeeeee
Мне часто приходится лишнюю строку чтобы программа завершилась (ещё и с Exceptions-ом)
думаю он тут нужен для того чтобы синхронизировать доступ к входящему потоку. без него все даже после интерупта потоки будут ждать ввода данных, потому что пройдут условия !isInterrupted() и reader.ready() и нет ничего что мешало бы им положить руку на входящий поток, просто посмотрите как работает с ним и без него
publicvoidrun(){//add your code here - добавьте код тутwhile(!isInterrupted()){synchronized(reader){try{if(reader.ready()){
result.add(reader.readLine());
readStringCount.getAndIncrement();}}catch(Exception e){}}}}
и без него
publicvoidrun(){//add your code here - добавьте код тутwhile(!isInterrupted()){try{if(reader.ready()){
result.add(reader.readLine());
readStringCount.getAndIncrement();}}catch(Exception e){}}}
в JDK есть исходники в архиве src.zipUPD: в IDEA просто Ctrl + B нажать когда курсор на имени класса или метода. (до этого я гуглил и попадал на docjar или openjdk)В моем случае он находится тут: C:\Program Files\Java\jdk1.8.0_151\src.zip\java\io\Reader.java C:\Program Files\Java\jdk1.8.0_151\src.zip\java\io\BufferedReader.javaТам можно посмотреть как устроены эти классы и что происходит при вызове методов ready() readLine() и close(). Ещё можно пользоваться дебаггером, но я пока не разобрался как дебажить многопоточные программы. Конечный вариант который я написал бы сейчас но я не могу его проверить, валидатор даёт повторно решать задачи только в течение непродолжительного времени.