Java线程打印多余行问题:最后线程重复输出唤醒信息
Java线程重复打印唤醒信息的问题分析与解决
问题现象
运行一个包含线程的Java程序,逻辑是让线程随机休眠一段时间后打印唤醒信息。程序执行到末尾时,最后一个线程的“is NOW AWAKE”信息被重复打印6次,其余线程均正常打印一次休眠和唤醒信息。
相关代码
sampleThread.java
import java.util.Random; public class sampleThread extends Thread{ sampleThread thread; Random rand = new Random(); public void run() { thread = new sampleThread(); int randSleep = rand.nextInt(1000); System.out.println(thread.getName() + " is sleeping for " + randSleep + " milliseconds"); try { Thread.sleep(randSleep); System.out.println(thread.getName() + " is NOW AWAKE"); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
driver.java
import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class driver { public static void main(String[] args) throws ExecutionException, InterruptedException { List<Future<?>> futArray = new ArrayList<>(); ExecutorService es = Executors.newFixedThreadPool(6); sampleThread temp = new sampleThread(); for (int i=0; i<120; i++) { Future<?> future = es.submit(temp); futArray.add(future); } } }
异常输出
Thread-117 is sleeping for 547 milliseconds Thread-117 is NOW AWAKE Thread-118 is sleeping for 442 milliseconds Thread-118 is NOW AWAKE Thread-119 is sleeping for 182 milliseconds Thread-119 is NOW AWAKE Thread-120 is sleeping for 487 milliseconds Thread-120 is NOW AWAKE Thread-120 is NOW AWAKE Thread-120 is NOW AWAKE Thread-120 is NOW AWAKE Thread-120 is NOW AWAKE Thread-120 is NOW AWAKE
原因分析
核心问题在于线程安全与变量作用域:
- 代码仅创建了一个
sampleThread实例temp,并将其重复提交给线程池120次。线程池的6个工作线程会并发调用这个实例的run方法。 sampleThread类中的thread是实例级成员变量,属于共享资源。当多个工作线程同时执行run方法时,会不断覆盖该变量的引用,最终所有线程的thread都会指向最后一次创建的sampleThread实例(即Thread-120)。- 当各个线程休眠结束后,打印的都是共享变量
thread的名称,因此出现了Thread-120的唤醒信息被重复打印6次(对应线程池的6个工作线程)的现象。
解决方案
将sampleThread类中的成员变量thread移至run方法内部,改为局部变量。这样每个线程执行run方法时,都会拥有独立的thread变量,不会相互干扰。
修改后的sampleThread.java代码:
import java.util.Random; public class sampleThread extends Thread{ Random rand = new Random(); public void run() { // 将thread改为run方法内的局部变量 sampleThread thread = new sampleThread(); int randSleep = rand.nextInt(1000); System.out.println(thread.getName() + " is sleeping for " + randSleep + " milliseconds"); try { Thread.sleep(randSleep); System.out.println(thread.getName() + " is NOW AWAKE"); } catch (InterruptedException e) { throw new RuntimeException(e); } } }
验证结果
修改后,每个线程的休眠和唤醒信息都会仅打印一次,不再出现重复输出的异常情况。
内容的提问来源于stack exchange,提问作者suttertub
相关产品推荐
相关产品推荐

