View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util.thread;
20  
21  import java.io.IOException;
22  import java.util.Arrays;
23  import java.util.List;
24  import java.util.concurrent.ScheduledFuture;
25  import java.util.concurrent.ScheduledThreadPoolExecutor;
26  import java.util.concurrent.ThreadFactory;
27  import java.util.concurrent.TimeUnit;
28  
29  import org.eclipse.jetty.util.component.AbstractLifeCycle;
30  import org.eclipse.jetty.util.component.ContainerLifeCycle;
31  import org.eclipse.jetty.util.component.Dumpable;
32  
33  /**
34   * Implementation of {@link Scheduler} based on JDK's {@link ScheduledThreadPoolExecutor}.
35   * <p />
36   * While use of {@link ScheduledThreadPoolExecutor} creates futures that will not be used,
37   * it has the advantage of allowing to set a property to remove cancelled tasks from its
38   * queue even if the task did not fire, which provides a huge benefit in the performance
39   * of garbage collection in young generation.
40   */
41  public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Scheduler, Dumpable
42  {
43      private final String name;
44      private final boolean daemon;
45      private final ClassLoader classloader;
46      private volatile ScheduledThreadPoolExecutor scheduler;
47      private volatile Thread thread;
48  
49      public ScheduledExecutorScheduler()
50      {
51          this(null, false);
52      }  
53  
54      public ScheduledExecutorScheduler(String name, boolean daemon)
55      {
56          this (name,daemon, Thread.currentThread().getContextClassLoader());
57      }
58      
59      public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
60      {
61          this.name = name == null ? "Scheduler-" + hashCode() : name;
62          this.daemon = daemon;
63          this.classloader = threadFactoryClassLoader;
64      }
65  
66      @Override
67      protected void doStart() throws Exception
68      {
69          scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactory()
70          {
71              @Override
72              public Thread newThread(Runnable r)
73              {
74                  Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(r, name);
75                  thread.setDaemon(daemon);
76                  thread.setContextClassLoader(classloader);
77                  return thread;
78              }
79          });
80          scheduler.setRemoveOnCancelPolicy(true);
81          super.doStart();
82      }
83  
84      @Override
85      protected void doStop() throws Exception
86      {
87          scheduler.shutdownNow();
88          super.doStop();
89          scheduler = null;
90      }
91  
92      @Override
93      public Task schedule(Runnable task, long delay, TimeUnit unit)
94      {
95          ScheduledThreadPoolExecutor s = scheduler;
96          if (s==null)
97              return new Task(){
98                  @Override
99                  public boolean cancel()
100                 {
101                     return false;
102                 }};
103 
104         ScheduledFuture<?> result = s.schedule(task, delay, unit);
105         return new ScheduledFutureTask(result);
106     }
107 
108     @Override
109     public String dump()
110     {
111         return ContainerLifeCycle.dump(this);
112     }
113 
114     @Override
115     public void dump(Appendable out, String indent) throws IOException
116     {
117         ContainerLifeCycle.dumpObject(out, this);
118         Thread thread = this.thread;
119         if (thread != null)
120         {
121             List<StackTraceElement> frames = Arrays.asList(thread.getStackTrace());
122             ContainerLifeCycle.dump(out, indent, frames);
123         }
124     }
125 
126     private class ScheduledFutureTask implements Task
127     {
128         private final ScheduledFuture<?> scheduledFuture;
129 
130         public ScheduledFutureTask(ScheduledFuture<?> scheduledFuture)
131         {
132             this.scheduledFuture = scheduledFuture;
133         }
134 
135         @Override
136         public boolean cancel()
137         {
138             return scheduledFuture.cancel(false);
139         }
140     }
141 }