java - 使用 JDK 8 编译但针对 JRE 7 的 ConcurrentHashMap 崩溃应用程序

标签 java iteration concurrenthashmap

我今天遇到了一个非常意外的错误,虽然我能够找到一种方法来解决整个问题,但我不确定我是否完全理解它为什么会这样做。

我正在使用的代码最初是用 JDK 7 环境编写的,当然是针对 JRE 7 的。在代码中,我使用了 ConcurrentHashMap。并且需要迭代 map 中的键。为此,我使用了 map.keySet()根据 JavaDocs 应该返回 Set<K> .在我们的构建环境切换到 JDK8 之前,这一切都很好。

当我们迁移到 JDK8 时,我确保在调用 javac 时调用 1.7 的目标/源。所以当代码想要遍历 map 的键时开始失败时,我感到非常惊讶。没有抛出错误,没有异常,线程只是简单地停止了。在做了一些研究之后,我发现 Java8 对 ConcurrentHashMap 的实现。 .keySet()方法返回 KeySetView<K,V> .

我通过切换使用 map.keySet() 解决了这个问题获得 Enumeration<K>使用 map.keys() .

现在我对问题的猜测是,虽然项目是针对 Java7 编译的,因为使用了 JDK8,但包含了 Java8 库,但是为什么它在遇到不匹配时没有抛出错误或异常?

这里是一个代码片段:

class MapProcessing
{
     private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<String, Object>();

     public MapProcessing()
     {
           map.put("First",new Object());
           map.put("Second",new Object());
           map.put("Third",new Object());
     } 


     public void processing()
     {
          // when calling this type of loop causes a freeze on our system.
          for(String key : map.keySet())
          {
              System.out.println(key);
          }
      }

     public void working()
     {
         // This is what I had to do to fix the problem.
         Enumeration<String> keys = map.keys();
         while(keys.hasMoreElements())
         {
              String key = keys.nextElement();
              System.out.println(key);
         }
     }
} 

我们正在使用 Oracle JDK 8 build 40 进行编译,在 Windows 2012 服务器上使用 1.7 的目标和 javac 中的源 1.7。

代码使用在 Windows 2012 服务器上运行的 Oracle JVM 7 build 25 运行。

最佳答案

如果我用 Java 8 和 javac -source 1.7 -target 1.8 编译你的代码,然后用 Java 7 运行它,我会得到一个

Exception in thread "main" java.lang.NoSuchMethodError:
  java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
    at stackoverflowt.Test.processing(Test.java:20)
    at stackoverflowt.Test.main(Test.java:27)   

This is because the the byte code looks like

public void processing();
    Code:
       0: aload_0       
       1: getfield      #4                  // Field map:Ljava/util/concurrent/ConcurrentHashMap;
       4: invokevirtual #10                 // Method java/util/concurrent/ConcurrentHashMap.keySet:()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
       7: invokevirtual #11                 // Method java/util/concurrent/ConcurrentHashMap$KeySetView.iterator:()Ljava/util/Iterator;
      10: astore_1      

and referring explicitly to ConcurrentHashMap$KeySetView which is not present in Java 7. I am on Mac with Java 1.7.0_79 and 1.8.0_45

If you change the code to (only use the Map Interface):

private Map<String, Object> map = new ConcurrentHashMap<String, Object>();

那么它对我有用。字节码看起来像

public void processing();
    Code:
       0: aload_0       
       1: getfield      #4                  // Field map:Ljava/util/Map;
       4: invokeinterface #10,  1           // InterfaceMethod java/util/Map.keySet:()Ljava/util/Set;
       9: invokeinterface #11,  1           // InterfaceMethod java/util/Set.iterator:()Ljava/util/Iterator;
      14: astore_1      

关于java - 使用 JDK 8 编译但针对 JRE 7 的 ConcurrentHashMap 崩溃应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32954041/

相关文章:

java - 数组应该比 ArrayList 快这么多吗?

java - Spring应用程序上下文无法加载配置文件

c - 递归循环

javascript - 如何遍历包含小于迭代器值的数组

java - 为什么concurrentHashMap需要一个Segment的数组?为什么它不能获取节点上的锁?

java - ConcurrentHashMap 超过容量

java - Scala:如何测试 mutable.Set 的并发性

java - 如何随机交换图像的像素?

java - 存储与映射中的键相对应的多个值

python - 如何使列表理解迭代函数