@Override
  public int run(String[] args) throws InterruptedException, ExecutionException, TimeoutException {

    /** a callback invoked when an asynchronous write fails. */
    final BufferedMutator.ExceptionListener listener = new BufferedMutator.ExceptionListener() {
      @Override
      public void onException(RetriesExhaustedWithDetailsException e, BufferedMutator mutator) {
        for (int i = 0; i < e.getNumExceptions(); i++) {
          LOG.info("Failed to sent put " + e.getRow(i) + ".");
        }
      }
    };

    BufferedMutatorParams params = new BufferedMutatorParams(TABLE).listener(listener)
      .setRequestAttribute("requestInfo", Bytes.toBytes("bar"));

    //
    // step 1: create a single Connection and a BufferedMutator, shared by all worker threads.
    //
    Map<String, byte[]> connectionAttributes = new HashMap<>();
    connectionAttributes.put("clientId", Bytes.toBytes("foo"));
    Configuration conf = getConf();
    try (
      final Connection conn = ConnectionFactory.createConnection(conf, null,
        AuthUtil.loginClient(conf), connectionAttributes);
      final BufferedMutator mutator = conn.getBufferedMutator(params)) {

      /** worker pool that operates on BufferedTable instances */
      final ExecutorService workerPool = Executors.newFixedThreadPool(POOL_SIZE);
      List<Future<Void>> futures = new ArrayList<>(TASK_COUNT);

      for (int i = 0; i < TASK_COUNT; i++) {
        futures.add(workerPool.submit(new Callable<Void>() {
          @Override
          public Void call() throws Exception {
            //
            // step 2: each worker sends edits to the shared BufferedMutator instance. They all use
            // the same backing buffer, call-back "listener", and RPC executor pool.
            //
            Put p = new Put(Bytes.toBytes("someRow"));
            p.addColumn(FAMILY, Bytes.toBytes("someQualifier"), Bytes.toBytes("some value"));
            mutator.mutate(p);
            // do work... maybe you want to call mutator.flush() after many edits to ensure any of
            // this worker's edits are sent before exiting the Callable
            return null;
          }
        }));
      }

      //
      // step 3: clean up the worker pool, shut down.
      //
      for (Future<Void> f : futures) {
        f.get(5, TimeUnit.MINUTES);
      }
      workerPool.shutdown();
      mutator.flush();
    } catch (IOException e) {
      // exception while creating/destroying Connection or BufferedMutator
      LOG.info("exception while creating/destroying Connection or BufferedMutator", e);
    } // BufferedMutator.close() ensures all work is flushed. Could be the custom listener is
      // invoked from here.
    return 0;
  }
An example of using the {@link BufferedMutator} interface.
hbase-examples/src/main/java/org/apache/hadoop/hbase/client/example/BufferedMutatorExample.java