Java大矩阵相加触发ArrayIndexOutOfBoundsException异常如何解决
问题根因
你遇到的ArrayIndexOutOfBounds异常核心是分块逻辑未适配奇数长度的矩阵边界,具体问题如下:
- 当前你固定按
N/2、M/2的步长拆分矩阵,Java整数除法会向下取整,当矩阵的行数N或列数M为奇数时,最后一次分块的边界会超出原矩阵的实际长宽,比如你示例中矩阵列数为7,M/2=3,最后一次分块的起始列d=6时,d+M/2=9远大于7,访问mat_A[i][j]时直接越界。 - 同样场景下,最后一块的实际行数/列数不足
N/2、M/2,循环中对submatrix[k][l]的访问也会超出子矩阵的索引范围。 - 额外说明:你当前在
thread.start()后直接调用thread.join(),多线程逻辑实际是串行执行的,没有发挥多线程的作用。
修复方案
方案1:适配动态块大小(推荐)
修改分块逻辑,每次计算当前块的实际高度和宽度,避免超出边界,同时调整线程等待逻辑发挥多线程作用,修改后的核心代码如下:
// 修改后的addmatrix方法 public static void addmatrix(int[][] mat_A,int[][] mat_B,int[][] submatrix1,int[][] submatrix2,int N,int M)throws Exception { ThreadOperation m1; ThreadOperation.initialize(N,M); ArrayList<Thread> threads = new ArrayList<Thread>(); int c=0,d; int blockHeight = N/2; int blockWidth = M/2; while(c<N) { // 计算当前块实际高度,避免超过总行数 int actualHeight = Math.min(blockHeight, N - c); d=0; while(d<M) { // 计算当前块实际宽度,避免超过总列数 int actualWidth = Math.min(blockWidth, M - d); int i=0,j=0,k,l; for(k=0,i=c; i < c + actualHeight; i++, k++) { for(l=0,j=d; j < d + actualWidth; j++, l++) { submatrix1[k][l]=mat_A[i][j]; submatrix2[k][l]=mat_B[i][j]; } } // ThreadOperation构造方法新增actualHeight、actualWidth参数,内部逻辑也适配实际尺寸访问 m1=new ThreadOperation(mat_A,mat_B,submatrix1,submatrix2,N,M,c,d,actualHeight,actualWidth); Thread thread =new Thread(m1); thread.start(); threads.add(thread); d=d+blockWidth; } c=c+blockHeight; } // 所有线程启动完成后统一等待执行结束 for(Thread t : threads){ t.join(); } } // 修改后的devidematrix方法 public static void devidematrix(int[][] mat_A,int[][] submatrix,int N,int M) { int c=0,d; int blockHeight = N/2; int blockWidth = M/2; while(c<N) { int actualHeight = Math.min(blockHeight, N - c); d=0; while(d<M) { int actualWidth = Math.min(blockWidth, M - d); int i=0,j=0,k,l; for( k=0,i=c;i < c + actualHeight;i++,k++) { for( l=0,j=d;j < d + actualWidth;j++,l++) { submatrix[k][l]=mat_A[i][j]; } } d=d+blockWidth; } c=c+blockHeight; } }
方案2:矩阵补0对齐
如果不想修改原有分块逻辑,可以先对输入矩阵做补0处理,将行数、列数都补为最近的偶数,计算完成后再截取前N行M列的结果即可,实现更简单。
内容的提问来源于stack exchange,提问作者Dazzleman
相关产品推荐
相关产品推荐

