使用ExecutorService提交任务前设置共享变量GENERAL_TIME报错求解决
解决ExecutorService任务共享GENERAL_TIME变量的问题
老哥,我猜你在多线程共享变量这块踩坑了——用ExecutorService提交任务时共享GENERAL_TIME变量,提交前设置却出问题,大概率是线程安全或者变量可见性的锅。我给你拆解几个常见场景和对应的解决办法:
1. 变量可见性:任务读不到最新的GENERAL_TIME
如果GENERAL_TIME是普通的成员变量(比如private static long GENERAL_TIME;),JVM的内存模型允许线程缓存变量副本,导致线程池里的工作线程可能看不到主线程刚设置的最新值。
解决办法:
- 给GENERAL_TIME加上
volatile修饰符:private static volatile long GENERAL_TIME;。volatile能强制所有线程直接从主内存读取变量,保证可见性,这种方式轻量,适合只需要可见性不需要复杂同步的场景。 - 或者用
synchronized同步块包裹设置和读取操作,但相比volatile会更重,除非你还需要原子性操作。
2. 想让任务用提交时的固定值?别共享,直接传参数!
如果你只是希望每个任务都使用提交那一刻的GENERAL_TIME值,那最安全的方式根本不是共享变量——而是把时间值作为参数直接传递给每个任务,彻底避免多线程共享的各种坑。
示例代码:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TaskWithTimeParam { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(3); // 先设置好要使用的时间值 long fixedGeneralTime = System.currentTimeMillis(); System.out.println("主线程确定的时间值: " + fixedGeneralTime); // 提交任务时把时间值传进去 for (int i = 0; i < 5; i++) { // Java 8+里lambda引用外部变量需为effectively final(后续不修改) long taskTime = fixedGeneralTime; executor.submit(() -> { // 直接用传递进来的taskTime,完全不依赖共享变量 System.out.println("当前任务使用的时间: " + taskTime); runTaskLogic(taskTime); }); } executor.shutdown(); } private static void runTaskLogic(long time) { // 这里写你的任务业务逻辑 } }
3. 共享的是对象?小心非线程安全类型!
如果GENERAL_TIME不是基本类型,而是一个非线程安全的对象(比如SimpleDateFormat、自定义的非线程安全实体类),那即使你提前设置好值,多个任务同时操作它也会出问题(比如格式错误、数据混乱)。
解决办法:
- 优先选择传递参数的方式,每个任务持有自己的对象实例;
- 如果必须共享,就给对象的访问加锁(比如用
synchronized包裹所有读写操作),或者替换成线程安全的类(比如用DateTimeFormatter代替SimpleDateFormat)。
4. 用volatile保证共享变量可见性的示例
如果你确实需要多个任务共享同一个可变的GENERAL_TIME值(比如后续主线程还要修改它,让任务读到最新值),可以用volatile:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SharedVolatileTime { // 用volatile保证可见性 private static volatile long GENERAL_TIME; public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(3); // 先设置初始值 GENERAL_TIME = System.currentTimeMillis(); System.out.println("主线程设置初始GENERAL_TIME: " + GENERAL_TIME); // 提交一批任务 for (int i = 0; i < 3; i++) { executor.submit(() -> { long time = GENERAL_TIME; System.out.println("任务读取到GENERAL_TIME: " + time); runTask(time); }); } // 模拟后续修改共享变量 Thread.sleep(1000); GENERAL_TIME = System.currentTimeMillis(); System.out.println("主线程更新GENERAL_TIME: " + GENERAL_TIME); // 再提交一批任务,会读到最新值 for (int i = 0; i < 3; i++) { executor.submit(() -> { long time = GENERAL_TIME; System.out.println("更新后任务读取到GENERAL_TIME: " + time); runTask(time); }); } executor.shutdown(); } private static void runTask(long time) { // 任务逻辑 } }
如果你的错误是具体的异常(比如ConcurrentModificationException、值不符合预期),可以把异常信息贴出来,能更精准定位,但上面的几种方案应该覆盖了大部分常见问题。
内容的提问来源于stack exchange,提问作者Soheil Pourbafrani
相关产品推荐
相关产品推荐

