求助:java.util.NoSuchElementException: No line found报错排查
java.util.NoSuchElementException: No line found 多线程坑 老哥,从你说的“无线程版本正常,改多线程就炸”这个情况来看,十有八九是多线程抢着读同一个输入流搞出来的问题,我帮你拆解几个最可能的原因和修复思路:
多线程共享输入流资源冲突
你无线程的时候,输入流(比如绑定System.in的InputStreamReader)是单线程独占的,读多少都没问题。但改成多线程后,如果每个Client线程都自己new Scanner(System.in)或者共用同一个BufferedReader实例,麻烦就来了——多个线程同时抢着读输入流,一个线程把剩下的内容读完了,另一个线程再调用readLine()/nextLine()时,发现流里已经没内容了,直接抛出这个异常。赶紧检查你的代码:是不是多个线程实例在直接操作同一个输入流对象?如果是,这就是核心问题。
输入流被某个线程提前关闭
多线程环境下,很容易出现某个线程执行完自己的逻辑后,顺手把输入流close()了,结果其他线程还等着读呢,一调用读取方法就炸。特别是如果你的无线程版本里有关闭流的逻辑,改多线程时没调整,就会踩这个坑。线程乱序导致的“超前读取”
无线程的时候,你是按顺序等着用户输入再处理,但多线程下线程调度是JVM说了算的,可能某个线程先跑起来,还没等用户输入内容就调用了读取方法,这时候输入流里没东西,自然就抛异常了。
快速修复思路
如果是共享输入流的问题,搞个单例的输入流管理器,让所有线程都通过它来读取,加锁保证同一时间只有一个线程读,就不会抢了:
// 全局输入流管理器,保证多线程安全读取 public class InputManager { private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); private static final Object lock = new Object(); // 所有线程都调用这个方法读输入 public static String readLine() throws IOException { synchronized (lock) { return reader.readLine(); } } // 这个close方法只在整个程序退出时调用,别在单个线程里瞎调用! public static void close() throws IOException { reader.close(); } }
然后你的Client线程里,别自己创建输入流了,直接用InputManager.readLine()来读取。另外,如果之前用的是Scanner,建议换成BufferedReader——因为Scanner的nextLine()在流空的时候会直接抛异常,而BufferedReader的readLine()会返回null,你可以判断null来做处理,更稳妥。
要是能把Client类里线程创建、输入读取的完整代码贴出来,我能帮你更精准定位,但根据你说的场景,多线程抢输入流是最可能的元凶。
内容的提问来源于stack exchange,提问作者Jordan O Donoghue

