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

使用Thread和Phaser实现数组并行变换结果异常排查

并行数组变换结果与串行不一致的问题分析

需要对数组执行m轮变换,变换规则为a[i]=(a[i-1]+a[i+1])/2,要求用Thread和Phaser实现,但编写的代码中串行算法与并行算法结果不一致,代码如下:

package lab3;

import java.util.concurrent.Phaser;

public class Program {
    public static void main(String[] args) 
    {
        int n = 100;
        int m = 100;
        int [] arr;
        arr = new int [n];
        int [] arr2;
        arr2 = new int [n];
        for (int i = 0; i<n; i++)
        {
            int r = (int)(Math.random()*50);
            arr [i] = r;
            arr2 [i] = r;
            System.out.print(arr[i]+" ");
        }
        int [] arr3 = arr2.clone();
        System.out.println(" ");
        // 串行实现
        for (int p = 0; p<m; p++)
            for (int i = 1; i<n-1; i++)
            {
                arr [i] = (arr [i-1]+arr [i+1])/2;
            }
        
        for (int i = 0; i<n; i++)
        {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
        // 并行实现
        Sum.arr = arr2;
        Sum.m=m;
        Phaser p = new Phaser();
            for (int i = 1; i<n-1; i++)
            {
                var x = new Sum (p, i);
                x.start();
            }
        // 直接打印,未等待线程完成
        for (int i = 0; i<n; i++)
        {
            System.out.print(Sum.arr[i]+" ");
        }
        System.out.println();
        // 结果对比
        for (int i = 0; i<n; i++)
        {
            if (arr[i]!=Sum.arr[i])
                System.out.println("Error! Value is incorrect at position: "+i+". Original val is: "+arr[i]+" Thread val is: "+Sum.arr[i]+" Before transform is: " +arr3[i]);
        }
    }
}

class Sum extends Thread 
{
    static int [] arr;
    static int m;
    Phaser ph;
    int i;
    
    public Sum(Phaser p, int i)
    {
        this.ph = p;
        this.i = i;
    }
    
    public static synchronized void trans (int i)
    {
        arr [i]= (arr [i-1]+arr [i+1])/2;
    }
    
    @Override
    public void run ()
    {
        ph.register();
        for (int j = 0; j<m; j++)
        {
            trans(i);
            ph.arriveAndAwaitAdvance();
        }
        ph.arriveAndDeregister();
    }
}

错误点分析

1. 同一轮内更新顺序混乱,违反串行逻辑

串行代码中,每一轮按i=1到n-2的顺序更新数组,后面的i(比如i=2)会用到前面i=1修改后的新值。但并行代码里,即便trans加了synchronized,线程执行顺序是随机的:比如i=2的线程先执行,用的是本轮初始的i=1、i=3值;之后i=1的线程执行时,i=2已经被修改,计算用的是被改动后的值,完全打乱了串行的依赖顺序,结果必然不一致。

2. 未隔离本轮计算的数据源

正确的轮次变换应该是:每一轮所有计算都基于上一轮的完整数组状态,不能直接在原数组上修改(否则同一轮内的计算会互相覆盖)。串行的顺序更新是其特定逻辑,但并行场景必须用双数组:一个存上一轮的输入数据,一个存本轮的计算结果;所有线程完成本轮计算后,再切换输入输出数组,确保同一轮计算都基于上一轮的原始值。

3. 主线程未等待并行任务完成

主线程启动所有线程后立刻打印Sum.arr,此时线程可能还在执行m轮变换,读取的是未完成的中间值,而串行是完成所有轮次后才打印,这直接导致结果对比时的不一致。

4. 同步方法让并行失效且顺序混乱

trans是静态同步方法,同一时间只有一个线程能执行,这不仅让并行退化成串行,而且线程执行顺序随机,和原串行的固定顺序完全不同,结果自然无法匹配。

内容的提问来源于stack exchange,提问作者Mikhail Kondaurov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:25:19