JNA回调方法仅在FutureTask.get()超时时才触发是什么原因?
问题成因
这是线程调度层面的互相等待问题,不属于Java对象监视器的死锁,核心原因如下:
- 厂商SDK的回调派发逻辑限制:绝大多数摄像头类硬件的Native SDK,默认会把回调事件绑定到
login方法的调用线程,依赖调用线程的空闲状态/内部消息队列来派发回调。你调用无参futureTask.get()时,当前线程直接进入永久阻塞状态,没有机会处理SDK内部的回调消息,因此回调代码块永远不会执行,形成「线程等回调执行future -> 回调等线程空闲才能派发」的僵持状态。 - 超时get的行为差异:使用带超时参数的
get方法时,1秒后方法会抛出TimeoutException,当前线程从阻塞状态被唤醒恢复执行,此时线程处于可处理消息的空闲状态,SDK排队的回调事件就可以正常派发执行,所以会出现超时后回调反而被触发的现象。
修复方案
- 方案1:单独启动子线程执行
login方法,不要阻塞回调依赖的调用线程
FutureTask<Long> futureTask = new FutureTask<>(System::currentTimeMillis); // 独立线程执行登录逻辑,不阻塞当前线程的消息处理 new Thread(() -> CameraSDk.login(ip, port, userName, password, (lLoginID, pBuf, RevLen, EncodeType, CmdSerial, dwUser) -> { // 回调处理逻辑 futureTask.run(); })).start(); try { Long timestamp = futureTask.get(); System.out.println("timestamp = " + timestamp); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
- 方案2:查询对应SDK的开发文档,将回调派发模式修改为独立线程派发,不需要绑定
login调用线程的状态。 - 方案3:如果是Windows平台的SDK,确保
login调用线程没有被长期阻塞,按文档要求定期处理消息循环。
内容的提问来源于stack exchange,提问作者King K
相关产品推荐
相关产品推荐

