我在@Async
方法注释中遇到了某种线程问题,其中一个参数包含一个List
枚举并且正在删除项目。清单很小,只有 2 项。物品的掉落不是立即的,但有时需要数小时或数天才能出现。
这是我们程序的一般流程:
A在其方法中Controller
生成上述,将列表传递给一个类,该类调用数据库进行批处理,并为数据库中的每个项目触发一个事件,传递列表。这个列表最终被传递到一个方法中,该方法然后删除第一个项目或两个项目。List
@RequestMapping
Service
@Async
Controller.methodA()
-> Creates list with two items in it
-> Calls void Service.methodX(list)
-> Load batch from database
-> Iterate over batch
-> Print items from list --- list in tact
-> Calls void AsyncService.asyncMethod(list)
-> Print items from list --- eventually drops items here always the first item, sometimes both.
代码配置和基本示例:
我们将其配置为具有 2 个线程:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(5); // Never actually creates 5 threads
threadPoolTaskExecutor.setCorePoolSize(2); // Only 2 threads are ever created
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
这是尝试触发核心问题的本地副本,但没有运气:
@RestController
public class ThreadingController {
private final ThreadingService threadingService;
public ThreadingController(ThreadingService threadingService) {
this.threadingService = threadingService;
}
@GetMapping("/test")
public void testThreads() {
List<SomeEnum> list = new ArrayList<>();
list.add(SomeEnum.FIRST_ENUM);
list.add(SomeEnum.SECOND_ENUM);
for (int i = 0; i < 1000; i++) {
this.threadingService.workSomeThreads(i, list);
}
}
}
public enum SomeEnum {
FIRST_ENUM("FIRST_ENUM"),
SECOND_ENUM("SECOND_ENUM");
@Getter
private String name;
SomeEnum(String name) {
this.name = name;
}
}
@Slf4j
@Service
public class ThreadingService {
@Async
public void workSomeThreads(int i, List<SomeEnum> list) {
try {
Thread.sleep(100L); // Add some delay to slow things down to trigger GC or other tests during processing
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("Count {} ; Here are the list items: {}", i, list.toString());
assert(list.size() == 2);
}
}
如果我们仔细研究一下,我有一个控制器来模拟前面提到的Controller
和。Service
它遍历一批数据,一遍又一遍地发送相同的列表。另一个类中有一个 aync 方法来测试列表是否相同。我无法在本地复制该问题,但这是核心问题。
据我所知,Java 是按引用传递的,传递给方法的每个变量都会在堆栈中获得自己的指针,指向内存中的该引用,但不要认为它会导致我们耗尽内存。我们在 PCF 中运行,在此期间看不到任何内存峰值或任何东西。内存保持在 50% 左右。我也尝试使用CopyOnWriteArrayList
(线程安全)代替,ArrayList
但问题仍然存在。
问题:
知道为什么该@Async
方法会在方法参数中删除项目吗?列表在构建后永远不会被修改,那么为什么项目会消失呢?为什么第一项总是消失?为什么不是第二项?为什么两者都会消失?
编辑:所以这个问题最终没有什么关系
@Async
。我发现深度嵌套的代码会从列表中删除项目,导致项目丢失。