多线程操作同一Floor_Layout实例引发数据异常问题求助
多线程共享实例导致数据干扰问题的解决方案
问题核心
你现在的两个线程共用同一个Floor_Layout实例,线程0修改了machineArr[0]的坐标后,线程1读取时拿到的是已经被修改过的数据,这是典型的多线程数据竞争——没有对共享资源的访问做隔离,导致线程间的操作互相干扰。你的预期是每个线程操作独立的初始布局,但实际因为共享实例,第二个线程的初始状态被第一个线程的修改覆盖了。
解决方案
方案1:给每个线程分配独立的布局副本
这是最适合遗传算法场景的方案——每个线程独立演化自己的布局,完全避免数据竞争。需要为Floor_Layout实现深拷贝,确保每个线程拿到的是和原始布局完全独立的实例。
步骤1:实现Floor_Layout的深拷贝
假设Machine类也需要拷贝坐标属性,先给Machine写拷贝构造方法,再给Floor_Layout实现拷贝逻辑:
class Machine { int oX, oY, aX, aY, lX, lY; // 拷贝构造方法,复制所有坐标属性 public Machine(Machine original) { this.oX = original.oX; this.oY = original.oY; this.aX = original.aX; this.aY = original.aY; this.lX = original.lX; this.lY = original.lY; } // 原有其他方法... } class Floor_Layout { Machine[] machineArr; // 其他成员变量... // 深拷贝构造方法 public Floor_Layout(Floor_Layout original) { // 复制Machine数组,每个元素都是独立拷贝 this.machineArr = new Machine[original.machineArr.length]; for (int i = 0; i < machineArr.length; i++) { this.machineArr[i] = new Machine(original.machineArr[i]); } // 复制其他二维数组或成员变量... } // 原有machineCord、moveMachineRand方法... }
步骤2:创建线程时传入独立副本
修改主线程中创建线程的代码,为每个线程生成原始布局的深拷贝:
public static void main(String[] args) { // 初始化原始布局 Floor_Layout originalFloor = new Floor_Layout(); // 给每个线程分配独立副本 Thread thread0 = new Thread(new Threads(new Floor_Layout(originalFloor))); Thread thread1 = new Thread(new Threads(new Floor_Layout(originalFloor))); thread0.start(); thread1.start(); }
这样每个线程操作的都是自己的布局实例,线程0的修改不会影响线程1的初始状态,就能得到你预期的输出。
方案2:对共享资源的操作加同步锁
如果必须多个线程共享同一个布局实例(比如后续需要合并线程的计算结果),可以通过同步锁保证每个线程的"读取初始坐标→修改→读取新坐标"是一个原子操作,不会被其他线程打断。
修改线程的run方法
class Threads implements Runnable { private Floor_Layout thisFloor; public Threads(Floor_Layout f) { thisFloor = f; } public void run() { try { // 对共享的布局实例加锁,同一时间只有一个线程能执行这段逻辑 synchronized(thisFloor) { thisFloor.machineCord(thisFloor.machineArr[0]); thisFloor.moveMachineRand(thisFloor.machineArr[0]); thisFloor.machineCord(thisFloor.machineArr[0]); } } catch (Exception e) { System.out.println("Exception is caught"); } } }
或者直接在Floor_Layout的方法中加锁:
class Floor_Layout { // 给方法加synchronized,保证同一时间只有一个线程能调用该方法 public synchronized void machineCord(Machine m) { // 原有打印坐标的逻辑 } public synchronized void moveMachineRand(Machine m) { // 原有随机移动坐标的逻辑 } }
这种方案会让线程串行执行同步块里的逻辑,避免数据竞争,但会损失多线程的并行性能,适合必须共享实例的场景。
原始问题代码
线程类代码
class Threads implements Runnable { boolean flag = false; private Floor_Layout thisFloor; Machine test1; public Threads(Floor_Layout f) { thisFloor = f; } public void run() { try { thisFloor.machineCord(thisFloor.machineArr[0]); thisFloor.moveMachineRand(thisFloor.machineArr[0]); thisFloor.machineCord(thisFloor.machineArr[0]); } catch (Exception e) { System.out.println("Exception is caught"); } } }
运行输出
Thread 0 Machine[0] oX,oy = 4,3 aX, aY = 5,3 lX,lY = 3,3 (this line) Thread 0 Machine[0] oX,oy = 3,1 aX, aY = 4,1 lX,lY = 2,1 Thread 1 Machine[0] oX,oy = 3,1 aX, aY = 4,1 lX,lY = 2,1 (and this line) Thread 1 Machine[0] oX,oy = 5,3 aX, aY = 6,3 lX,lY = 4,3
内容的提问来源于stack exchange,提问作者Kieran Rudolph
相关产品推荐
相关产品推荐

