You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何并发执行带参exchange方法?解决Java变量final报错问题

解决Bitonic排序中exchange方法并发调用的变量final报错问题

问题原因

Java中,匿名内部类(比如你创建的Thread子类)访问外部作用域的局部变量时,该变量必须是final或者effectively final(即变量初始化后未被重新赋值)。你的循环变量i在每次迭代中都会被修改,不符合这个要求,因此编译器报错。

解决方案

在循环内部创建局部变量保存当前迭代的i值,该变量在单次迭代中不会被修改,属于effectively final,可被匿名内部类安全访问:

修改后的merge方法代码

static void merge(int beg, int c, int d) {
    if (c > 1) {
        int k = c / 2;

        // 替换原串行for循环为并行线程调用
        Thread[] t = new Thread[k];
        for (int i = beg; i < beg + k; i++) {
            int currentI = i; // 保存当前i的值,成为effectively final变量
            t[i - beg] = new Thread() {
                @Override
                public void run() {
                    exchange(a, currentI, currentI + k, d);
                }
            };
            t[i - beg].start();
        }

        // 等待所有exchange线程执行完成
        for (Thread thread : t) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        Thread t1 = new Thread() {
            @Override
            public void run() {
                merge(beg, k, d);
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                merge(beg + k, k, d);
            }
        };
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

优化建议:使用线程池减少线程开销

直接为每个exchange创建线程会带来大量线程创建、销毁的性能损耗,建议用ExecutorService线程池优化:

static void merge(int beg, int c, int d) {
    if (c > 1) {
        int k = c / 2;

        // 根据CPU核心数创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        for (int i = beg; i < beg + k; i++) {
            int currentI = i;
            executor.submit(() -> exchange(a, currentI, currentI + k, d));
        }
        executor.shutdown();
        // 等待所有exchange任务完成
        try {
            if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            e.printStackTrace();
        }

        Thread t1 = new Thread() {
            @Override
            public void run() {
                merge(beg, k, d);
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                merge(beg + k, k, d);
            }
        };
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程安全性说明

exchange方法操作静态数组a,但每个线程处理的是唯一的索引对(currentI, currentI + k),这些索引对无重叠,不会出现并发修改同一数组元素的情况,是线程安全的。

内容的提问来源于stack exchange,提问作者GUMMALLA DRONA SAI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:22:48