如何不使用Callable调用ArrayList<Thread>中Runnable的getter获取tempCounter?
嘿,我来帮你捋清楚这个问题~你遇到的“符号未找到”错误,以及想调用ArrayList内Runnable方法的需求,其实都可以通过自定义子类或者线程安全的共享变量来解决,下面给你详细拆解:
为什么直接访问tempCounter会报错?
你收到“符号未找到”错误,大概率是这两个原因:
- 你的
primeThread里的tempCounter是私有变量,外部类PrimeCounter没有访问权限; - 如果
primeThread是匿名Runnable或者lambda表达式,编译器只会把它当成Runnable接口实例,而接口里并没有tempCounter这个成员,自然找不到对应的符号。
不用Callable,怎么获取Runnable的计算结果?
这里有两种实用的方案:
方案1:自定义Runnable子类,提供getter方法
自己写一个继承自Runnable的类,把计算结果存在成员变量里,再写一个getter方法让外部获取:
// 自定义PrimeRunnable类 class PrimeRunnable implements Runnable { private int tempCounter; // 存储当前线程的质数统计结果 @Override public void run() { // 这里写你的质数计算逻辑,把统计结果赋值给tempCounter tempCounter = 0; for (int i = 2; i < 100; i++) { if (isPrime(i)) { tempCounter++; } } } // 提供getter方法,让外部获取计算结果 public int getTempCounter() { return tempCounter; } // 辅助方法:判断是否为质数 private boolean isPrime(int num) { if (num <= 1) return false; for (int i = 2; i <= Math.sqrt(num); i++) { if (num % i == 0) return false; } return true; } }
然后在PrimeCounter里,必须等待线程执行完毕后,再通过getter拿结果累加:
public class PrimeCounter { public static void main(String[] args) throws InterruptedException { int counter = 0; List<PrimeRunnable> threadList = new ArrayList<>(); // 创建并启动多个PrimeRunnable线程 for (int i = 0; i < 4; i++) { PrimeRunnable runnable = new PrimeRunnable(); threadList.add(runnable); new Thread(runnable).start(); } // 等待所有线程完成,再累加结果 for (PrimeRunnable runnable : threadList) { runnable.join(); // 等待当前线程执行完 counter += runnable.getTempCounter(); } System.out.println("总质数数量:" + counter); } }
⚠️ 注意:一定要调用join(),不然线程还没跑完就去拿tempCounter,得到的会是初始值0或者不正确的结果。
方案2:用线程安全的共享变量直接累加
如果不想写自定义Runnable子类,可以用AtomicInteger这种线程安全的原子类,让每个线程直接把计算结果加到共享变量里:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class PrimeCounter { public static void main(String[] args) throws InterruptedException { AtomicInteger totalCounter = new AtomicInteger(0); List<Thread> threadList = new ArrayList<>(); for (int i = 0; i < 4; i++) { Thread thread = new Thread(() -> { int temp = 0; // 质数计算逻辑 for (int num = 2; num < 100; num++) { if (isPrime(num)) { temp++; } } // 原子性地把temp加到总计数器里 totalCounter.addAndGet(temp); }); threadList.add(thread); thread.start(); } // 等待所有线程完成 for (Thread thread : threadList) { thread.join(); } System.out.println("总质数数量:" + totalCounter.get()); } private static boolean isPrime(int num) { if (num <= 1) return false; for (int i = 2; i <= Math.sqrt(num); i++) { if (num % i == 0) return false; } return true; } }
这种方法不用事后去每个线程里拿结果,直接在计算完后自动累加,还避免了多线程环境下的竞态问题。
能不能在PrimeCounter中调用ArrayList内的Runnable方法?
当然可以,但有个前提:你的Runnable必须是自定义的子类实例,而不是匿名内部类或者lambda。因为如果是lambda/匿名Runnable,编译器只认为它是Runnable接口的实现,而接口里只有run()方法,你没法调用自定义的方法。
举个例子,如果你的ArrayList里存的是PrimeRunnable实例,但声明的是ArrayList<Runnable>,那需要先强转类型再调用方法:
ArrayList<Runnable> runnables = new ArrayList<>(); runnables.add(new PrimeRunnable()); // 遍历调用自定义方法 for (Runnable r : runnables) { if (r instanceof PrimeRunnable) { int count = ((PrimeRunnable) r).getTempCounter(); // 处理count } }
不过更规范的做法是直接把ArrayList的泛型声明为ArrayList<PrimeRunnable>,这样就不用强转,代码更安全。
内容的提问来源于stack exchange,提问作者adoino

