hadoop reduce阶段 对象重用问题

张开发
2026/4/10 4:04:11 15 分钟阅读

分享文章

hadoop reduce阶段 对象重用问题
问题根源对象重用Hadoop 为了优化性能在reduce方法中会重用key和value对象。这意味着在for(Person p : values)循环中变量p始终指向同一个Person对象实例。框架在每次迭代时会用新的数据覆盖这个Person对象的内部属性而不是创建一个新的对象。因此当你执行plist.add(p)时你只是将同一个对象的引用多次添加到了列表plist中。最终plist里所有的元素都指向内存中的同一个Person对象而这个对象的值是最后一次迭代时被覆盖的结果。错误代码示例假设values中包含三个Person对象其name属性分别为 Alice、Bob 和 Charlie。ListPerson plist new ArrayList(); for(Person p : values){ plist.add(p); }执行后plist的内容将不是[Alice, Bob, Charlie]。相反plist中会包含三个指向同一个对象的引用而这个对象的name属性是Charlie。所以遍历plist会得到[Charlie, Charlie, Charlie]。正确的解决方案你需要创建一个新的Person对象副本然后将副本添加到列表中。这样列表中的每个元素都是一个独立的对象。方法一手动创建新对象并复制属性这是最直接的方法适用于所有情况。ListPerson plist new ArrayList(); for(Person p : values){ // 创建一个新的Person对象 Person newPerson new Person(); // 手动复制所有需要的属性 newPerson.setName(p.getName()); newPerson.setAge(p.getAge()); // ... 复制其他属性 // 将新对象的引用添加到列表中 plist.add(newPerson); }方法二使用工具类复制属性如果你的Person类有很多属性可以使用像 Apache Commons BeanUtils 这样的工具类来简化属性复制过程。import org.apache.commons.beanutils.BeanUtils; ListPerson plist new ArrayList(); for(Person p : values){ Person newPerson new Person(); try { // 自动复制所有同名同类型的属性 BeanUtils.copyProperties(newPerson, p); } catch (Exception e) { e.printStackTrace(); } plist.add(newPerson); }方法三实现拷贝构造函数在你的Person类中定义一个拷贝构造函数可以使代码更简洁。public class Person implements Writable { private String name; private int age; // 默认的无参构造函数Hadoop序列化需要 public Person() {} // 拷贝构造函数 public Person(Person other) { this.name other.name; this.age other.age; } // ... 其他代码 (getter, setter, write, readFields) }然后在reduce方法中这样使用ListPerson plist new ArrayList(); for(Person p : values){ // 使用拷贝构造函数创建副本 plist.add(new Person(p)); }

更多文章