Если вы используете тот же экземпляр сканера в двух потоках, у вас возникнут проблемы, если вы не синхронизируете доступ к объекту. Но два отдельных экземпляра сканера никогда не будут мешать друг другу.
редактировать в ответ на комментарий с вопросом, как синхронизировать
Во-первых, вы действительно уверены, что вам нужно синхронизировать на всех? Вы можете безопасно использовать разные экземпляры сканера в разных потоках без какой-либо опасности. Один поток может иметь
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»; что было бы бесполезно.
Мои предложения для синхронизации этого:
- Не многопоточности! Даже ампутация частей тела предпочтительнее, чтобы сделать многопоточное приложение стабильным, масштабируемым и гибким!
- Иногда вы можете подклассифицировать класс, не поддерживающий потоки (или инкапсулировать и делегировать), и синхронизировать вызовы с базовым классом (или делегировать):
synchronised (this) { super.next(); }
. Но не пробуйте это со Сканером! Существует так много потребительских методов, и вы не представляете, как класс реализован внутри, так что вы обречены на провал! См. Предложение 1.
- Что бы я попытался сделать здесь, есть один поток, запускающий сканер и подающий токены в ArrayBlockingQueue. Таким образом, вы получите полные токены, входящие в очередь в правильном порядке. Вы можете иметь столько потоков, сколько хотите читать из очереди. Но имейте в виду, что любой из ваших потоков может быть заблокирован как для чтения, так и для записи этой очереди, если вы не будете заниматься полными и пустыми условиями. Скорее всего, что независимо от того, что вы делаете, у вас появятся оборванные нити, которые никогда не закончатся. См. Пункт 1. Это усложнится, если вы хотите иногда называть разные методы следующим образом: (см.
nextInt()
, nextDouble()
) или использовать имеет методы (например, hasNextInt()
hasNextDouble()
), но не так сложно, как точка 2.
Наконец, я хотел бы предложить вам увидеть точку 1.
Не они не будут. –