ConcurrentHashMap崩溃使用JDK 8编译但是以JRE 7为目标的应用程序 [英] ConcurrentHashMap crashing application compiled with JDK 8 but targeting JRE 7

查看:311
本文介绍了ConcurrentHashMap崩溃使用JDK 8编译但是以JRE 7为目标的应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



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



我通过切换使用 map.keySet()修复了问题使用 map.keys()获取枚举< K>



现在我对问题的猜测是,虽然项目是针对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()
{
//调用这种类型的循环会导致系统冻结。
for(String key:map.keySet())
{
System.out.println(key);
}
}

public void working()
{
//这是解决问题所必须做的事情。
枚举< String> keys = map.keys();
while(keys.hasMoreElements())
{
String key = keys.nextElement();
System.out.println(key);
}
}
}

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



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

解决方案

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

 
线程main中的异常java.lang.NoSuchMethodError:
java.util.concurrent.ConcurrentHashMap.keySet( )Ljava / UTIL /并发/ ConcurrentHashMap的$ KeySetView; stackoverflowt.Test.processing(Test.java:20)
at stackoverflowt.Test.main $ $ $ $ $ $
$ /

这是因为字节代码看起来像

 
public void processing();
代码:
0:aload_0
1:getfield#4 //字段映射:Ljava / util / concurrent / ConcurrentHashMap;
4:invokevirtual#10 //方法java / util / concurrent / ConcurrentHashMap.keySet :()Ljava / util / concurrent / ConcurrentHashMap $ KeySetView;
7:invokevirtual#11 //方法java / util / concurrent / ConcurrentHashMap $ KeySetView.iterator :()Ljava / util / Iterator;
10:astore_1

并明确引用Java 7中不存在的ConcurrentHashMap $ KeySetView。我在Mac上使用Java 1.7.0_79和1.8.0_45



如果您将代码更改为(仅使用地图界面):

 私有地图< String,Object> map = new ConcurrentHashMap< String,Object>(); 

然后它适用于我。 Bytecode然后看起来像

 
public void processing();
代码:
0:aload_0
1:getfield#4 //字段映射: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


I ran into a very unexpected error today and while I was able to find a way to fix the problem as a whole I'm not sure I completely understand why it did what it did.

The code I'm working with was originally written with a JDK 7 environment of course targeting JRE 7. In the code I was using a ConcurrentHashMap and needed to iterate over the keys in the map. For this I was using the map.keySet() which according to the JavaDocs should return a Set<K>. This worked fine until our build environment switched to JDK8.

When we moved to JDK8 I ensured that I was calling a target/source for 1.7 when calling the javac. So I was pretty surprised when the code started failing right when it wanted to iterate through the keys of the map. No error was thrown, no exception, the thread just simply stopped. After doing some research I found that Java8's implementation for ConcurrentHashMap the .keySet() method returns a KeySetView<K,V>.

I fixed the problem by switching from using the map.keySet() to getting an Enumeration<K> using map.keys().

Now my guess as to the problem is that although the project was compiled targeting Java7 since the JDK8 was used the Java8 libraries were included, but why didn't it thrown an error or an exception when it hit the mismatch?

As asked here is a code snippet:

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);
         }
     }
} 

We are compiling using Oracle JDK 8 build 40 using a target for 1.7 and source 1.7 in the javac on a Windows 2012 server.

The code is running using Oracle JVM 7 build 25 running on Windows 2012 server.

解决方案

If i compile your code with Java 8 and javac -source 1.7 -target 1.8 and then run it with Java 7 i get an

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>();

then it work's for me. Bytecode then looks like

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      

这篇关于ConcurrentHashMap崩溃使用JDK 8编译但是以JRE 7为目标的应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆