2015-06-24 3 views
3

Я заинтересован в использовании java.util.Scanner. Я читал docs и видел линию, в которой сканер небезопасен для многопоточного использования без внешней синхронизации. Могу ли я подтвердить, что это означает, что два отдельных объекта Сканера в двух отдельных потоках, работающих в двух отдельных файлах, могут мешать друг другу?Является ли сканер в java не потокобезопасным?

Может ли кто-нибудь помочь мне синхронизировать объект сканера извне, чтобы использовать его для безопасной работы нити?

+1

Не они не будут. –

ответ

2

Если вы используете тот же экземпляр сканера в двух потоках, у вас возникнут проблемы, если вы не синхронизируете доступ к объекту. Но два отдельных экземпляра сканера никогда не будут мешать друг другу.

редактировать в ответ на комментарий с вопросом, как синхронизировать

Во-первых, вы действительно уверены, что вам нужно синхронизировать на всех? Вы можете безопасно использовать разные экземпляры сканера в разных потоках без какой-либо опасности. Один поток может иметь
Scanner s1 = new Scanner (new File ("/tmp/file1.txt");
и другой поток может иметь
Scanner s2 - new Scanner (new File ("/tmp/file2.txt"));
и нет никакого риска. Различные сканеры могут использовать один и тот же файл, разные файлы или совершенно разные источники данных. Однако вам все равно нужно быть осторожным. Как отмечено Stephen C below, вы по-прежнему будете разорваны, если два отдельных экземпляра сканера используют один и тот же поток или считыватель в качестве их ввода, тогда они будут красть символы друг от друга. Это предупреждение относится к конструкторам, использующим InputStream, Readable и ReadableByteChannel.

Проблема с использованием одного сканера в нескольких потоках заключается в том, что он последовательно потребляет символы из одного источника. Если у вас несколько потоков, потребляющих эти символы в несинхронизированном режиме, каждый поток будет получать некоторые из символов, и ни один из потоков не получит все символы. Чтобы проиллюстрировать: представьте, что у вас есть сканер, читающий строку «qwertyuiop», и два отдельных потока каждой функции вызова next() одновременно, тогда один поток может видеть «ertip», а другой поток получит «qwyuo»; что было бы бесполезно.

Мои предложения для синхронизации этого:

  1. Не многопоточности! Даже ампутация частей тела предпочтительнее, чтобы сделать многопоточное приложение стабильным, масштабируемым и гибким!
  2. Иногда вы можете подклассифицировать класс, не поддерживающий потоки (или инкапсулировать и делегировать), и синхронизировать вызовы с базовым классом (или делегировать): synchronised (this) { super.next(); }. Но не пробуйте это со Сканером! Существует так много потребительских методов, и вы не представляете, как класс реализован внутри, так что вы обречены на провал! См. Предложение 1.
  3. Что бы я попытался сделать здесь, есть один поток, запускающий сканер и подающий токены в ArrayBlockingQueue. Таким образом, вы получите полные токены, входящие в очередь в правильном порядке. Вы можете иметь столько потоков, сколько хотите читать из очереди. Но имейте в виду, что любой из ваших потоков может быть заблокирован как для чтения, так и для записи этой очереди, если вы не будете заниматься полными и пустыми условиями. Скорее всего, что независимо от того, что вы делаете, у вас появятся оборванные нити, которые никогда не закончатся. См. Пункт 1. Это усложнится, если вы хотите иногда называть разные методы следующим образом: (см.nextInt(), nextDouble()) или использовать имеет методы (например, hasNextInt()hasNextDouble()), но не так сложно, как точка 2.

Наконец, я хотел бы предложить вам увидеть точку 1.

+0

Можете ли вы указать, как синхронизировать объект сканера извне, чтобы использовать для безопасной работы потока? –

0

Многопоточное использование относится к двум потокам, работающим на одном объекте. Два потока, работающие на двух разных объектах, прекрасны.

0

Вы можете использовать несколько сканеры, использующие разные источники данных из нескольких потоков без проблем.

Использование один сканер с с несколькими потоками приведет к проблемам.

1

Я хочу, чтобы поднять на данный момент в принятом ответе.

Если вы используете тот же экземпляр сканера в двух потоках, у вас возникнут проблемы, если вы не синхронизируете доступ к объекту. Но два отдельных экземпляра сканера никогда не будут мешать друг другу.

На самом деле, два отдельных Scanner экземпляры могут мешать друг другу, если они имеют один и тот же источник входного сигнала. Подумайте, есть ли у вас два объекта сканера, обертывающие System.in, используемые двумя отдельными потоками. Когда вы вызываете hasNextInt() на один Scanner, он будет читать от System.in достаточно символов, чтобы определить, что существует действительное целое число. Если первый поток затем не вызывал nextInt(), второй поток не смог бы прочитать символы с чтением. Они будут сидеть во внутренних буферах первого Scanner.

В сущности, один сканер мешая другим путем «воруют» символов. Наличие двух сканеров в одном потоке является патологическим. Ваше утверждение справедливо только для двух сканеров на разных входных потоках.

+0

Хорошая точка ... вы абсолютно правы. –

Смежные вопросы