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 final ThreadGroup threadGroup;
47      private volatile ScheduledThreadPoolExecutor scheduler;
48      private volatile Thread thread;
49  
50      public ScheduledExecutorScheduler()
51      {
52          this(null, false);
53      }  
54  
55      public ScheduledExecutorScheduler(String name, boolean daemon)
56      {
57          this (name,daemon, Thread.currentThread().getContextClassLoader());
58      }
59      
60      public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
61      {
62          this(name, daemon, threadFactoryClassLoader, null);
63      }
64  
65      public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader, ThreadGroup threadGroup)
66      {
67          this.name = name == null ? "Scheduler-" + hashCode() : name;
68          this.daemon = daemon;
69          this.classloader = threadFactoryClassLoader == null ? Thread.currentThread().getContextClassLoader() : threadFactoryClassLoader;
70          this.threadGroup = threadGroup;
71      }
72  
73      @Override
74      protected void doStart() throws Exception
75      {
76          scheduler = new ScheduledThreadPoolExecutor(1, new ThreadFactory()
77          {
78              @Override
79              public Thread newThread(Runnable r)
80              {
81                  Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(threadGroup, r, name);
82                  thread.setDaemon(daemon);
83                  thread.setContextClassLoader(classloader);
84                  return thread;
85              }
86          });
87          scheduler.setRemoveOnCancelPolicy(true);
88          super.doStart();
89      }
90  
91      @Override
92      protected void doStop() throws Exception
93      {
94          scheduler.shutdownNow();
95          super.doStop();
96          scheduler = null;
97      }
98  
99      @Override
100     public Task schedule(Runnable task, long delay, TimeUnit unit)
101     {
102         ScheduledThreadPoolExecutor s = scheduler;
103         if (s==null)
104             return new Task(){
105                 @Override
106                 public boolean cancel()
107                 {
108                     return false;
109                 }};
110 
111         ScheduledFuture<?> result = s.schedule(task, delay, unit);
112         return new ScheduledFutureTask(result);
113     }
114 
115     @Override
116     public String dump()
117     {
118         return ContainerLifeCycle.dump(this);
119     }
120 
121     @Override
122     public void dump(Appendable out, String indent) throws IOException
123     {
124         ContainerLifeCycle.dumpObject(out, this);
125         Thread thread = this.thread;
126         if (thread != null)
127         {
128             List<StackTraceElement> frames = Arrays.asList(thread.getStackTrace());
129             ContainerLifeCycle.dump(out, indent, frames);
130         }
131     }
132 
133     private static class ScheduledFutureTask implements Task
134     {
135         private final ScheduledFuture<?> scheduledFuture;
136 
137         ScheduledFutureTask(ScheduledFuture<?> scheduledFuture)
138         {
139             this.scheduledFuture = scheduledFuture;
140         }
141 
142         @Override
143         public boolean cancel()
144         {
145             return scheduledFuture.cancel(false);
146         }
147     }
148 }