title: How to implement a FIFO queue in a multi-threaded environment
body: <p>I am trying to implement a queue for a class that fetches <code>OpenGraph</code> data for a url.  The idea is that the <code>OpenGraphIO</code> service only allows for one request at a time if the request requires their "proxy" service. To eliminate the "simultaneous proxy request" errors from the service, I would like to implement a request queue inside a service class called <code>OpenGraphFetcherImpl</code>.  However, I can't figure out how to implement the actual queue itself inside the <code>fetch()</code> method.  Obviously the <code>fetch()</code> method can be called in a multi-threaded environment. </p>
  
  <p>My class shell is below:</p>
  
  <pre><code>public class OpenGraphFetcherImpl implements OpenGraphFetcher {
  
      private static final String[] domainsThatRequireProxy = {"instagram.com","facebook.com"};
  
      private static final LinkedList&lt;URL&gt; proxyQueue = new LinkedList&lt;&gt;();
  
      private final String api_key;
  
      public OpenGraphFetcherImpl(String api_key) {
          this.api_key = api_key;
      }
  
      /**
       * Fetch OpenGraph information for a url.  If the url is invalid or no data is returned, the OpenGraph
       * object will be "empty" (non-null)
       * 
       * Only one "proxy" request can be made at a time. Should a proxy be needed, the request will be queued
       * and returned once previous requests have been completed.
       *
       * @param url end point to fetch OpenGraph data
       * @return OpenGraph object
       */
      @Override
      @Nonnull
      public OpenGraph fetch(URL url) {
          if (useProxy(url)) {
              // Clearly this code doesn't work, but logic should be to add the request to the queue and then make requests in FIFO order
              proxyQueue.add(url);
              return OpenGraphIO.fetchOpenGraphInfo(api_key, proxyQueue.poll(), true);
          } else {
              return OpenGraphIO.fetchOpenGraphInfo(api_key, url, false);
          }
      }
  
      /**
       * @param url url to test
       * @return true if the host of the url matches any domains that require use of a proxy
       */
      private boolean useProxy(URL url) {
          return Arrays.stream(domainsThatRequireProxy).parallel().anyMatch(url.getHost()::contains);
      }
  }
  </code></pre>