View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.zookeeper;
20  
21  import java.util.concurrent.CountDownLatch;
22  
23  /**
24   * Placeholder of an instance which will be accessed by other threads
25   * but is not yet created. Thread safe.
26   */
27  class InstancePending<T> {
28    // Based on a subtle part of the Java Language Specification,
29    // in order to avoid a slight overhead of synchronization for each access.
30  
31    private final CountDownLatch pendingLatch = new CountDownLatch(1);
32  
33    /** Piggybacking on {@code pendingLatch}. */
34    private InstanceHolder<T> instanceHolder;
35  
36    private static class InstanceHolder<T> {
37      // The JLS ensures the visibility of a final field and its contents
38      // unless they are exposed to another thread while the construction.
39      final T instance;
40  
41      InstanceHolder(T instance) {
42        this.instance = instance;
43      }
44    }
45  
46    /**
47     * Returns the instance given by the method {@link #prepare}.
48     * This is an interruptible blocking method
49     * and the interruption flag will be set just before returning if any.
50     */
51    T get() {
52      InstanceHolder<T> instanceHolder;
53      boolean interrupted = false;
54  
55      while ((instanceHolder = this.instanceHolder) == null) {
56        try {
57          pendingLatch.await();
58        } catch (InterruptedException e) {
59          interrupted = true;
60        }
61      }
62  
63      if (interrupted) {
64        Thread.currentThread().interrupt();
65      }
66      return instanceHolder.instance;
67    }
68  
69    /**
70     * Associates the given instance for the method {@link #get}.
71     * This method should be called once, and {@code instance} should be non-null.
72     * This method is expected to call as soon as possible
73     * because the method {@code get} is uninterruptibly blocked until this method is called.
74     */
75    void prepare(T instance) {
76      assert instance != null;
77      instanceHolder = new InstanceHolder<T>(instance);
78      pendingLatch.countDown();
79    }
80  }