【问题标题】:Java 8 automatically using multicore?Java 8 自动使用多核?
【发布时间】:2015-04-18 20:07:06
【问题描述】:

一年前我用 java 7 做了一些关于多核的测试。首先我只在主线程中实现了一些计算(CPU 使用率表明只有一个核心完成了所有工作),然后我用 ExecutorService 实例实现了 Callable。在运行它时,所有核心都在做这项工作。

现在,一年后,我必须实现一个插入大量数据的小程序(使用 java 8)。所有工作都在主线程中实现(没有 Callable 和 ExecutorService),但是当我运行程序时,CPU 使用率显示,所有 4 个内核都在 98%。

那么 java 8 会自动将工作分配到所有 CPU 内核上吗?我很困惑...

这里有一些代码...

MapGenerator.java

    Region[][] regions = new Region[numOfRegions][numOfRegions];

    for(int x = 0; x < regions.length; x++){
        for(int z = 0; z < regions[x].length; z++){
            newLat = SRTMHandler.getNewLatitude(startLat, z * regionSize * 16);
            newLon = SRTMHandler.getNewLongitude(startLon, x * regionSize * 16, newLat);

            regions[x][z] = new Region(x, z, regionSize, newLat, newLon);
        }
    }

Region.java:

private Chunk[] chunks;    

public Region(int x, int z, int size, float startLat, float startLon){
    this.chunks = new Chunk[this.size][this.size];
    //Init stuff
    float newLat = this.startLat, newLon = this.startLon;

    for(int newX = 0; newX < this.size; newX++){
        for(int newZ = 0; newZ < this.size; newZ++){
            newLat = SRTMHandler.getNewLatitude(this.startLat, newZ * 16);
            newLon = SRTMHandler.getNewLongitude(this.startLon, newX * 16, newLat);

            this.chunks[newX][newZ] = new Chunk(this.x * this.size + newX, this.z * this.size + newZ, 16, 900, this, newLat, newLon);
        }
    }
}

Chunk.java:(SRTMHandler.getHeightForLatLon() 进行一些地理计算,然后读取字节数组中的值,没什么特别的)

public Chunk(int x, int z, int size, int height, Region r, float startLat, float startLon){
    this.blocks = new Block[size][size][height];
    //Init stuff

    try {
        this.calcSurface();
        //System.out.println("Finished " + this.toString());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void calcSurface() throws IOException{
    int x1 = this.x;
    int x2 = this.x + 16;
    int z1 = this.z;
    int z2 = this.z + 16;
    final int radius = 45;
    float q11 = SRTMHandler.getHeightForLatLon(SRTMHandler.getNewLatitude(this.startLat, (-1)*radius), SRTMHandler.getNewLongitude(this.startLon, (-1)*radius, this.startLat));
    float q12 = SRTMHandler.getHeightForLatLon(SRTMHandler.getNewLatitude(this.startLat, radius), SRTMHandler.getNewLongitude(this.startLon, (-1)*radius, this.startLat));
    float q21 = SRTMHandler.getHeightForLatLon(SRTMHandler.getNewLatitude(this.startLat, (-1)*radius), SRTMHandler.getNewLongitude(this.startLon, radius, this.startLon));
    float q22 = SRTMHandler.getHeightForLatLon(SRTMHandler.getNewLatitude(this.startLat, radius), SRTMHandler.getNewLongitude(this.startLon, radius, this.startLat));

    for(int x = 0; x < this.blocks.length; x++){
        for(int z = 0; z < this.blocks[x].length; z++){
            float height = Interpolation.biLerp(x, z, q11, q12, q21, q22, x1, x2, z1, z2);

            this.blocks[x][z][(int)Math.round(height)] = new Block(this.x * this.size + x, this.z * this.size + z, (int)Math.round(height), BlockType.Grass, this);
        }
    }
}

【问题讨论】:

  • 您是否在使用 Java 8 的函数式编程特性,特别是并行流?
  • 当 aparapi/parallelforall 完全提供时,甚至 gpus 也可以使用 java-only 代码 lambdas 自动使用。
  • 能否提供一个小代码示例?
  • 我没有明确的答案,但有两个提示:垃圾收集可能并行发生;要查找进程中处于活动状态的线程,请尝试在运行时附加 jvisualvm。
  • 我们应该如何知道SRTMHandler 中的这些方法是做什么的?

标签: java multithreading multiprocessing java-8 multicore


【解决方案1】:

我也遇到过这种情况。就我而言,频繁的垃圾回收会导致 CPU 使用率很高(98%)。正如几个cmet在原始问题下指出的那样,java GC默认使用多线程。

在我看来,您的程序不受 CPU 限制。因此,不太可能完全使用 4 核。另一方面,当没有足够的堆空间分配给你的程序时,频繁的 GC 很容易耗尽 CPU 资源。增加堆大小后,一切都很好。

【讨论】:

    【解决方案2】:

    Java 8 不会自动将工作分配到所有 CPU 内核上,除非您的代码明确请求(例如通过使用并行流)。

    在某些特殊情况下,Hotspot 编译器会auto-vectorize 代码,例如JDK-6340864。但是,自动矢量化使用特殊的SIMD CPU 指令,而不是多个 CPU。

    另请参阅以下答案:

    (请注意,我重写了答案,删除了由 cmets 更正的部分)

    【讨论】:

    • 编译器会做一些有限的自动向量化,这是一种自动并行化的形式。
    • 当您对大型矩阵进行操作时,Matlab 会自动进行并行化。它在必要时使用所有内核。
    • 我想找到一个证据:“除非您的代码明确要求它(例如通过使用并行流)”。 java如何从操作系统显式请求内核上的线程分布模式?这合理吗?我认为只有操作系统才能控制这些事情。
    • @VladimirNabokov Java 不要求线程在特定处理器上运行,这确实是操作系统的工作。但是如果要使用所有内核,则需要手动启动足够多的线程:OS和Java都不会自动启动线程。
    • @VladimirNabokov 是的,我从未说过这是 Java 的力量。请阅读原始问题:尽管只使用一个线程,但该操作在所有内核中都经历了 CPU 使用情况。我的回答应该在这种情况下解释。
    猜你喜欢
    • 2011-06-14
    • 1970-01-01
    • 2016-08-30
    • 2014-08-30
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2016-01-13
    相关资源
    最近更新 更多