Loop yang menjumlahkan jutaan angka umumnya memproses satu elemen per langkah — padahal CPU modern memproses operasi pada 8, 16, bahkan 32 angka sekaligus lewat instruksi SIMD (AVX, SVE, NEON). Selama bertahun-tahun, Java hanya bisa menikmati kecepatan itu secara tidak langsung lewat optimasi otomatis compiler atau keluar ke pustaka native. Vector API, yang dirancang sejak Java 16 di bawah JEP 338 dan kini memasuki incubator kesepuluhnya lewat JEP 508 di Java 25, membawa gaya lanewise programming ke Java: satu operasi pada seluruh elemen sebuah vektor sekaligus. Chapter ini memperkenalkan konsepnya dengan simulasi murni Java yang bisa dijalankan langsung, lalu menampilkan wujud asli API — yang masih incubator dan perlu flag khusus.

Konsep Lane dan Operasi Lanewise #

Unit dasarnya adalah Vector<E>: wadah berisi lane sebanyak lebar register SIMD. Sebuah IntVector ber-16 lane menampung 16 nilai int; operasi a.add(b) menjumlahkan lane ke-n dari a dan b secara serentak — satu pemanggilan method, enam belas penjumlahan. Lebar lane optimal ditentukan CPU lewat VectorSpecies, misalnya IntVector.SPECIES_PREFERRED; kode yang sama berjalan pada register 128-bit hingga 512-bit tanpa penyesuaian manual, karena API memilih bentuk terbaik saat runtime.

Simulasi Konsep Lane dalam Java Murni #

Sebelum menyentuh API sungguhan, mari kita tiru polanya dengan array biasa: loop scalar memproses satu elemen, loop “lanewise” memproses potongan empat elemen per langkah:

public class SimulasiLane {

    // Lebar lane ilustratif: peniruan konsep, bukan SIMD sungguhan.
    static final int LANE = 4;

    public static void main(String[] args) {
        int[] data = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8};

        // 1) Loop scalar: satu elemen diproses per langkah.
        long totalScalar = 0;
        int langkahScalar = 0;
        for (int nilai : data) {
            totalScalar += (long) nilai * nilai;
            langkahScalar++;
        }

        // 2) Loop "lanewise": satu potongan 4 elemen per langkah.
        long totalLane = 0;
        int langkahLane = 0;
        for (int basis = 0; basis < data.length; basis += LANE) {
            int[] potongan = new int[LANE];
            for (int i = 0; i < LANE; i++) {
                potongan[i] = data[basis + i]; // muat satu lane penuh
            }
            long jumlahLane = 0;
            for (int i = 0; i < LANE; i++) {
                jumlahLane += (long) potongan[i] * potongan[i]; // kuadrat per lane
            }
            totalLane += jumlahLane;
            langkahLane++;
        }

        System.out.println("total scalar : " + totalScalar);
        System.out.println("total lane   : " + totalLane);
        System.out.println("langkah loop scalar: " + langkahScalar);
        System.out.println("langkah loop lane  : " + langkahLane);
    }
}

Output yang Dihasilkan:

text
total scalar : 296
total lane   : 296
langkah loop scalar: 12
langkah loop lane  : 3

Bedah baris-per-baris untuk bagian pentingnya:

  1. Konstanta LANE = 4: lebar potongan ilustratif — dalam SIMD sungguhan angka ini ditentukan VectorSpecies dan bisa 8, 16, atau 32 tergantung CPU.
  2. Loop pertama: dua belas langkah untuk dua belas elemen; setiap langkah menghitung kuadrat satu nilai — inilah loop scalar klasik.
  3. Loop kedua (basis += LANE): hanya tiga langkah karena empat elemen dimuat sekaligus per potongan; jumlah langkah loop pembawa berkurang empat kali lipat meski total kerja per elemen tetap sama.
  4. Baris total lane : 296: hasil identik dengan jalur scalar — invarian yang sama dijamin Vector API sungguhan: hasil matematis tidak berubah, hanya cara CPU mengeksekusinya.

Wujud Asli Vector API #

Kode berikut memakai API sungguhan — masih incubator sehingga ditampilkan tanpa klaim keluaran otomatis dari tool Course ini, tetapi telah dijalankan di JDK 25 untuk memastikan kebenarannya:

java JumlahKuadrat.java (membutuhkan --add-modules jdk.incubator.vector)
import jdk.incubator.vector.IntVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;

public class JumlahKuadrat {

    static final VectorSpecies<Integer> SPESIES = IntVector.SPECIES_PREFERRED;

    static long jumlahKuadrat(int[] data) {
        long total = 0;
        int i = 0;
        // loopBound: panjang terbesar yang habis dibagi lebar lane.
        int batas = SPESIES.loopBound(data.length);
        for (; i < batas; i += SPESIES.length()) {
            IntVector v = IntVector.fromArray(SPESIES, data, i);
            total += v.mul(v).reduceLanesToLong(VectorOperators.ADD);
        }
        // Ekor: sisa elemen yang tidak memenuhi satu lane penuh.
        for (; i < data.length; i++) {
            total += (long) data[i] * data[i];
        }
        return total;
    }

    public static void main(String[] args) {
        int[] data = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3};
        System.out.println("lane          : " + SPESIES.length());
        System.out.println("jumlah kuadrat: " + jumlahKuadrat(data));
    }
}

Jalankan dengan modul incubator aktif:

bash
java --add-modules jdk.incubator.vector JumlahKuadrat.java

Pada pengujian di JDK 25 dengan CPU 512-bit, program mencetak jumlah kuadrat: 516 — angka yang sama dengan versi scalar untuk data tersebut, sementara nilai lane mengikuti lebar register CPU mesin eksekusi. Tiga idiom pentingnya: loopBound memisahkan bagian array yang habis dibagi lebar lane, fromArray/intoArray memindahkan data masuk-keluar vektor, dan loop ekor yang tetap scalar menangani sisa — pola wajib karena panjang data dunia nyata jarang habis dibagi.

Status Incubator dan Kapan Memakainya #

AspekKeterangan
Status di Java 25Incubator kesepuluh (JEP 508)
Flag wajib--add-modules jdk.incubator.vector
Jaminan APIBelum ada — signature dapat berubah antar rilis
Target penggunaPustaka performa tinggi, bukan aplikasi bisnis biasa

Komputasi vektor menutup sisi performa. Bab berikutnya kembali ke tata kelola task konkuren dengan structured concurrency — masih berstatus preview di Java 25 dan karenanya dibahas sebagai konsep dengan penanda flag.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

SimulasiLane.java

Unduh berkas
java
public class SimulasiLane {

    // Lebar lane ilustratif: peniruan konsep, bukan SIMD sungguhan.
    static final int LANE = 4;

    public static void main(String[] args) {
        int[] data = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8};

        // 1) Loop scalar: satu elemen diproses per langkah.
        long totalScalar = 0;
        int langkahScalar = 0;
        for (int nilai : data) {
            totalScalar += (long) nilai * nilai;
            langkahScalar++;
        }

        // 2) Loop "lanewise": satu potongan 4 elemen per langkah.
        long totalLane = 0;
        int langkahLane = 0;
        for (int basis = 0; basis < data.length; basis += LANE) {
            int[] potongan = new int[LANE];
            for (int i = 0; i < LANE; i++) {
                potongan[i] = data[basis + i]; // muat satu lane penuh
            }
            long jumlahLane = 0;
            for (int i = 0; i < LANE; i++) {
                jumlahLane += (long) potongan[i] * potongan[i]; // kuadrat per lane
            }
            totalLane += jumlahLane;
            langkahLane++;
        }

        System.out.println("total scalar : " + totalScalar);
        System.out.println("total lane   : " + totalLane);
        System.out.println("langkah loop scalar: " + langkahScalar);
        System.out.println("langkah loop lane  : " + langkahLane);
    }
}