@Override
    public void run() {
      try {
        long rowKeyBase;
        byte[][] columnFamilies = dataGenerator.getColumnFamilies();
        while ((rowKeyBase = nextKeyToWrite.getAndIncrement()) < endKey) {
          byte[] rowKey = dataGenerator.getDeterministicUniqueKey(rowKeyBase);
          Put put = new Put(rowKey);
          numKeys.addAndGet(1);
          int columnCount = 0;
          for (byte[] cf : columnFamilies) {
            byte[][] columns = dataGenerator.generateColumnsForCf(rowKey, cf);
            for (byte[] column : columns) {
              byte[] value = dataGenerator.generateValue(rowKey, cf, column);
              put.addColumn(cf, column, value);
              ++columnCount;
              if (!isMultiPut) {
                insert(table, put, rowKeyBase);
                numCols.addAndGet(1);
                put = new Put(rowKey);
              }
            }
            long rowKeyHash = Arrays.hashCode(rowKey);
            put.addColumn(cf, MUTATE_INFO, HConstants.EMPTY_BYTE_ARRAY);
            put.addColumn(cf, INCREMENT, Bytes.toBytes(rowKeyHash));
            if (!isMultiPut) {
              insert(table, put, rowKeyBase);
              numCols.addAndGet(1);
              put = new Put(rowKey);
            }
          }
          if (isMultiPut) {
            if (verbose) {
              LOG.debug("Preparing put for key = [" + Bytes.toString(rowKey) + "], " + columnCount
                + " columns");
            }
            insert(table, put, rowKeyBase);
            numCols.addAndGet(columnCount);
          }
          if (trackWroteKeys) {
            wroteKeys.add(rowKeyBase);
          }
        }
      } finally {
        closeHTable();
        numThreadsWorking.decrementAndGet();
      }
    }
Use multi-puts vs. separate puts for every column in a row
hbase-diagnostics/src/main/java/org/apache/hadoop/hbase/util/MultiThreadedWriter.java