java中的扫描程序不是线程安全的吗?

时间:2015-06-24 10:31:38

标签: java thread-safety java.util.scanner

我对使用java.util.Scanner感兴趣。我正在阅读docs并看到一条线说没有外部同步,扫描仪对于多线程使用是不安全的。我是否可以确认这意味着在两个单独文件中运行的两个独立线程中的两个单独的Scanner对象可能会相互干扰?

任何人都可以帮我在外部同步扫描仪对象以用于安全的线程操作吗?

4 个答案:

答案 0 :(得分:2)

如果在两个线程中使用相同的Scanner实例,除非您同步对象的访问权限,否则会遇到问题。但是两个独立的扫描仪实例永远不会相互干扰。

编辑以回复询问如何同步的评论

首先,您确定需要同步吗?您可以安全地在不同的线程中使用不同的扫描仪实例,一个线程可以有 Scanner s1 = new Scanner (new File ("/tmp/file1.txt");
另一个线程可以有 Scanner s2 - new Scanner (new File ("/tmp/file2.txt"));
而且没有风险。不同的扫描仪可以使用相同的文件,不同的文件或完全不同的数据源。你仍然需要谨慎。正如Stephen C below所指出的,如果两个独立的Scanner实例使用相同的流或读取器作为输入,那么它们仍然会被破坏,然后它们会相互窃取字符。此警告适用于使用InputStream,Readable和ReadableByteChannel的构造函数。

在多个线程中使用单个扫描程序的问题是它从单个源顺序消耗字符。如果你有多个线程以不同步的方式使用这些字符,那么每个线程将获得一些字符,并且没有线程将获得所有字符。举例说明:想象一下,你有一个扫描仪读取字符串" qwertyuiop",两个独立的线程同时调用函数next(),然后一个线程可能会看到" ertip"另一个线程会得到" qwyuo&#34 ;;这将是无用的。

我同步的建议是:

  1. 不要多线程!甚至截断身体部位也是优选的,试图使多线程应用程序稳定,可扩展和灵活!
  2. 有时您可以子类化非线程安全类(或封装和委托)并将调用同步到基类(或委托):synchronised (this) { super.next (); }。但不要试用Scanner!有很多消费者方法,你不知道这个类是如何在内部实现的,所以你注定要失败!见建议1。
  3. 我在这里尝试做的是让一个线程运行Scanner并将令牌送入ArrayBlockingQueue。这样,您将以正确的顺序获得完整的令牌进入队列。您可以从队列中读取任意数量的线程。但请注意,除非您注意处理完整和空白条件,否则您的任何线程都可能被阻止读取或写入此队列。有可能无论你做什么,你都会得到永无止境的悬挂线。请参阅第1点。如果您希望有时调用不同的下一个方法(例如nextInt()nextDouble())或使用 has 方法,这将变得复杂(例如hasNextInt()hasNextDouble()),但不像第2点那么复杂。
  4. 最后,我建议你看一下第1点。

答案 1 :(得分:1)

我想在接受的答案中接受这一点。

  

如果在两个线程中使用相同的Scanner实例,除非您同步对象的访问权限,否则会遇到问题。 但是,两个独立的扫描仪实例绝不会相互干扰。

实际上,如果共享相同的输入源,则两个单独的Scanner实例可以相互干扰。考虑是否有两个Scanner对象包装由两个不同线程使用的System.in。当您在hasNextInt()上调用Scanner时,它将从System.in足够的字符开始向前读取,以确定是否存在有效整数。如果第一个线程没有调用nextInt(),则第二个线程将无法读取预读字符。它们将位于第一个Scanner的内部缓冲区中。

实际上,一个Scanner通过“窃取”字符来干扰另一个。在同一个流上有两个扫描仪是病态的。您的声明仅适用于不同输入流上的两个扫描仪。

答案 2 :(得分:0)

多线程使用是指在同一对象上运行的两个线程。在两个不同的对象上运行的两个线程很好。

答案 3 :(得分:0)

您可以使用多个扫描程序使用来自多个线程的不同数据源而不会出现问题。

一个扫描程序多个帖子一起使用会导致问题。