View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package net.sf.ehcache.transaction.xa.processor;
17  
18  import java.util.concurrent.BrokenBarrierException;
19  import java.util.concurrent.Callable;
20  import java.util.concurrent.CyclicBarrier;
21  import java.util.concurrent.ExecutionException;
22  import java.util.concurrent.ExecutorService;
23  import java.util.concurrent.Executors;
24  
25  /***
26   * Fast and minimalistic thread pool from which threads can be reserved and used many times until they
27   * are manually released.
28   *
29   * @author Ludovic Orban
30   */
31  public class XAThreadPool {
32  
33      private final ExecutorService executor = Executors.newCachedThreadPool();
34  
35      /***
36       * Reserve a thread from the pool
37       * @return a MultiRunner which wraps the reserved thread
38       */
39      public synchronized MultiRunner getMultiRunner() {
40          MultiRunner multiRunner = new MultiRunner();
41          executor.submit(multiRunner);
42          return multiRunner;
43      }
44  
45      /***
46       * Shutdown the thread pool and release all resources
47       */
48      public synchronized void shutdown() {
49          executor.shutdown();
50      }
51  
52      /***
53       * Pooled thread wrapper which allows reuse of the same thread
54       */
55      public static final class MultiRunner implements Runnable {
56          private final CyclicBarrier startBarrier = new CyclicBarrier(2);
57          private final CyclicBarrier endBarrier = new CyclicBarrier(2);
58          private volatile Callable callable;
59          private volatile boolean released;
60          private volatile Object result;
61  
62          private MultiRunner() {
63          }
64  
65          /***
66           * Execute a Callable on the wrapped thread and return its result
67           * @param callable The Callable to execute
68           * @return the Object returned by the Callable
69           * @throws ExecutionException thrown when something went wrong during execution
70           * @throws InterruptedException thrown when the executing thread got interrupted
71           */
72          public Object execute(Callable callable) throws ExecutionException, InterruptedException {
73              if (released) {
74                  throw new IllegalStateException("MultiRunner has been released");
75              }
76              if (callable == null) {
77                  throw new NullPointerException("callable cannot be null");
78              }
79  
80              try {
81                  this.callable = callable;
82                  startBarrier.await();
83  
84                  endBarrier.await();
85                  return result;
86              } catch (BrokenBarrierException e) {
87                  throw new ExecutionException("error executing " + callable, e);
88              }
89          }
90  
91          /***
92           * Release the wrapped thread back the the containing thread pool
93           */
94          public void release() {
95              try {
96                  callable = null;
97                  released = true;
98                  startBarrier.await();
99              } catch (InterruptedException e) {
100                 // ignore
101             } catch (BrokenBarrierException e) {
102                 // ignore
103             }
104         }
105 
106         /***
107          * {@inheritDoc}
108          */
109         public void run() {
110             try {
111                 while (true) {
112                     startBarrier.await();
113 
114                     if (callable != null) {
115                         result = callable.call();
116                         endBarrier.await();
117                     } else {
118                         return;
119                     }
120                 }
121             } catch (Exception e) {
122                 released = true;
123                 e.printStackTrace();
124             }
125         }
126     }
127 
128 }