除了在 Java 中使用参数之外,在方法调用之间传递数据的最有效方法是什么?

发布于 2025-01-09 00:40:13 字数 681 浏览 0 评论 0原文

我正在为一个特定的测试目的检测一个 Android 项目。我希望在方法调用之间传输一些信息(例如,infoObj 对象)。因此基本思想是在调用方法之前使用映射(通过线程 id 索引以避免并发问题)存储 infoObj,然后从映射中检索 infoObj在被调用方法体的开头。

例如,这里有两个方法 f1f2,其中 f1 调用 f2

void f1() {
  f2();
}

void f2() {
}

检测后,它们会变成:

void f1() {
  map.put(threadID, infoObj); // put infoObj into the map before invoking f2
  f2();
}

void f2() {
  map.remove(threadID); // get infoObj from the map at the beginning of f2
}

在大多数情况下效果很好。但是,当方法调用发生在长循环中时,检测后的程序的运行速度会比原始程序慢得多。使用参数来传输是最好的解决方案,但不幸的是我无法修改方法定义,因为程序语义可能会改变。

实现我的目标最有效的解决方案是什么?

I'm instrumenting a Android project for a specific testing purpose. I hope to transfer some information (e.g., an infoObj object) between method invocations. So the basic idea is to use a map (indexed by thread id to avoid concurrency issues) to store the infoObj before invoking a method, and then retrieve the infoObj from the map at the beginning of the invoked method body.

For example, here are two methods f1 and f2 where f1 invokes f2.

void f1() {
  f2();
}

void f2() {
}

After instrumenting, they become:

void f1() {
  map.put(threadID, infoObj); // put infoObj into the map before invoking f2
  f2();
}

void f2() {
  map.remove(threadID); // get infoObj from the map at the beginning of f2
}

It works well in most of the cases. But when method invocations occur in a long loop, the instrumented program runs much slower than its original one. Using parameters to transfer is the best solution but unfortunately I cannot modify method definitions because program semantics may change.

What is the most efficient solution to achieve my goal?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

潜移默化 2025-01-16 00:40:13

在 Java 中确实没有一个好的方法来做到这一点。主要问题是,如果您有多个线程,则需要一个映射,并且映射的使用成本相当昂贵,因为它们必须计算哈希值并在内部数据结构中定位项目。

请注意,HashMap 也不是线程安全的。您还没有说明是否已确保其安全(例如,使用Collections.synchronizedMap)。如果有,那么最好使用 ConcurrentHashMap,它比同步的 HashMap 快得多。如果没有,使其成为线程安全只会让它变得更慢。

顺便说一句,ThreadLocal 有其自己的内部自定义映射实现。我想这是为了性能而做的,而且它一定比使用 HashMap 更快(否则为什么要麻烦呢?)。因此,为什么你会看到它变慢是一个谜,除非你没有同步,这可能会解释它。

我可以建议一些事情:

  1. 您也许可以通过预测您所在的线程来避免这个问题。我不是 Android 方面的专家,但通常某些代码只能在某些线程中,并且可能没有除非您自己启动,否则会发生大量多线程。如果是这种情况,您只需为该代码点创建一个特定的静态并直接引用它。
  2. 如果您无法避免使用地图,您可以在互联网上搜索更快的地图实现。
  3. 可以在其他地方进行 put 操作吗?写入映射是最慢的部分,因此如果您可以为线程预先填充它,则可能会加快速度。您也不希望在检测代码中分配内存(调用 new),因此请确保 infoObj 已预先分配并在每次调用时重新使用它。

There isn't really a good way of doing this in Java. The main problem is that if you have multiple threads you need a map and maps are moderately expensive to use due to them having to calculate hashes and locate the item in the internal data structures.

Note that HashMap is also not thread-safe. You haven't said whether you have made it safe (e.g., using Collections.synchronizedMap). If you have, then you are better using ConcurrentHashMap which is much faster than a synchronized HashMap. If you haven't, making it thread-safe will only make it slower.

Incidentally, ThreadLocal has its own internal custom map implementation. I would imagine this is done for performance and that it must be faster than using HashMap (else why bother?). So why you are seeing it as slower is a puzzle, unless you are not synchronizing, which might explain it.

I can suggest a few things:

  1. You might be able to avoid the issue by predicting which thread you are in. I am not an expert on Android, but quite often certain bits of code can only be in certain threads and there might not be a lot of multi-threading going on unless you initiated it yourself. If that is the case you can just create a specific static for that code-point and reference it directly.
  2. If you can't avoid using maps, you could scour the internet for faster map implementations.
  3. Can you do the put operation elsewhere? Writing to a map is the slowest part, so if you can pre-populate it for the thread, that might speed things up. You also don't want to be allocating memory (calling new) in your instrumentation code, so make sure infoObj is pre-allocated and re-use it on each call.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文