diff --git a/api/src/main/java/net/md_5/bungee/api/scheduler/ScheduledTask.java b/api/src/main/java/net/md_5/bungee/api/scheduler/ScheduledTask.java index 9e8dae07..bc40b889 100644 --- a/api/src/main/java/net/md_5/bungee/api/scheduler/ScheduledTask.java +++ b/api/src/main/java/net/md_5/bungee/api/scheduler/ScheduledTask.java @@ -1,6 +1,5 @@ package net.md_5.bungee.api.scheduler; -import java.util.concurrent.TimeUnit; import net.md_5.bungee.api.plugin.Plugin; /** @@ -31,11 +30,7 @@ public interface ScheduledTask Runnable getTask(); /** - * Get the delay in the specified unit before this task will next be - * executed. - * - * @param unit the unit to get the delay in - * @return the time before the next execution of this task + * Cancel this task to suppress subsequent executions. */ - long getDelay(TimeUnit unit); + void cancel(); } diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index f8e054b8..853948c1 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -28,7 +28,6 @@ import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Timer; import java.util.TimerTask; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -50,7 +49,6 @@ import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.PluginManager; -import net.md_5.bungee.api.scheduler.TaskScheduler; import net.md_5.bungee.api.tab.CustomTabList; import net.md_5.bungee.command.*; import net.md_5.bungee.config.YamlConfig; @@ -60,7 +58,6 @@ import net.md_5.bungee.protocol.packet.DefinedPacket; import net.md_5.bungee.protocol.packet.Packet3Chat; import net.md_5.bungee.protocol.packet.PacketFAPluginMessage; import net.md_5.bungee.protocol.Vanilla; -import net.md_5.bungee.scheduler.BungeeThreadPool; import net.md_5.bungee.tab.Custom; import net.md_5.bungee.util.CaseInsensitiveMap; import org.fusesource.jansi.AnsiConsole; @@ -83,10 +80,6 @@ public class BungeeCord extends ProxyServer * Localization bundle. */ public final ResourceBundle bundle = ResourceBundle.getBundle( "messages_en" ); - /** - * Thread pools. - */ - public final ScheduledThreadPoolExecutor executors = new BungeeThreadPool( new ThreadFactoryBuilder().setNameFormat( "Bungee Pool Thread #%1$d" ).build() ); public final MultithreadEventLoopGroup eventLoops = new NioEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); /** * locations.yml save thread. @@ -117,7 +110,7 @@ public class BungeeCord extends ProxyServer @Getter private final File pluginsFolder = new File( "plugins" ); @Getter - private final TaskScheduler scheduler = new BungeeScheduler(); + private final BungeeScheduler scheduler = new BungeeScheduler(); @Getter private ConsoleReader consoleReader; @Getter @@ -288,8 +281,6 @@ public class BungeeCord extends ProxyServer { BungeeCord.this.isRunning = false; - executors.shutdown(); - stopListeners(); getLogger().info( "Closing pending connections" ); @@ -329,6 +320,7 @@ public class BungeeCord extends ProxyServer getScheduler().cancel( plugin ); } + scheduler.shutdown(); getLogger().info( "Thankyou and goodbye" ); System.exit( 0 ); } diff --git a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java index 6ce993f4..d6a849f5 100644 --- a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java +++ b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeScheduler.java @@ -4,14 +4,16 @@ import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import gnu.trove.TCollections; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.ScheduledTask; import net.md_5.bungee.api.scheduler.TaskScheduler; @@ -19,16 +21,21 @@ import net.md_5.bungee.api.scheduler.TaskScheduler; public class BungeeScheduler implements TaskScheduler { + private final ExecutorService s = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat( "Bungee Pool Thread #%1$d" ).build() ); private final AtomicInteger taskCounter = new AtomicInteger(); private final TIntObjectMap tasks = TCollections.synchronizedMap( new TIntObjectHashMap() ); private final Multimap tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.create() ); + public void shutdown() + { + s.shutdown(); + } + @Override public void cancel(int id) { BungeeTask task = tasks.remove( id ); tasksByPlugin.values().remove( task ); - task.getFuture().cancel( false ); } @Override @@ -61,21 +68,17 @@ public class BungeeScheduler implements TaskScheduler @Override public ScheduledTask schedule(Plugin owner, Runnable task, long delay, TimeUnit unit) { - return prepare( owner, task ).setFuture( BungeeCord.getInstance().executors.schedule( task, delay, unit ) ); + return schedule( owner, task, delay, 0, unit ); } @Override public ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit) - { - return prepare( owner, task ).setFuture( BungeeCord.getInstance().executors.scheduleWithFixedDelay( task, delay, period, unit ) ); - } - - private BungeeTask prepare(Plugin owner, Runnable task) { Preconditions.checkNotNull( owner, "owner" ); Preconditions.checkNotNull( task, "task" ); - BungeeTask prepared = new BungeeTask( taskCounter.getAndIncrement(), owner, task ); + BungeeTask prepared = new BungeeTask( this, taskCounter.getAndIncrement(), owner, task, delay, period, unit ); tasks.put( prepared.getId(), prepared ); + s.execute( prepared ); return prepared; } } diff --git a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java index c132bf0e..6fb80843 100644 --- a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java +++ b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeTask.java @@ -1,32 +1,75 @@ package net.md_5.bungee.scheduler; -import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import lombok.AccessLevel; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; import lombok.Data; -import lombok.Setter; +import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.ScheduledTask; @Data -public class BungeeTask implements ScheduledTask +public class BungeeTask implements Runnable, ScheduledTask { + private final BungeeScheduler sched; private final int id; private final Plugin owner; private final Runnable task; - @Setter(AccessLevel.NONE) - private ScheduledFuture future; + // + private final long delay; + private final long period; + private final AtomicBoolean running = new AtomicBoolean( true ); + + public BungeeTask(BungeeScheduler sched, int id, Plugin owner, Runnable task, long delay, long period, TimeUnit unit) + { + this.sched = sched; + this.id = id; + this.owner = owner; + this.task = task; + this.delay = unit.toMillis( delay ); + this.period = unit.toMillis( period ); + } @Override - public long getDelay(TimeUnit unit) + public void cancel() { - return future.getDelay( unit ); + running.set( false ); } - BungeeTask setFuture(ScheduledFuture future) + @Override + public void run() { - this.future = future; - return this; + if ( delay > 0 ) + { + try + { + Thread.sleep( delay ); + } catch ( InterruptedException ex ) + { + Thread.currentThread().interrupt(); + } + } + + while ( running.get() ) + { + try + { + task.run(); + } catch ( Throwable t ) + { + ProxyServer.getInstance().getLogger().log( Level.SEVERE, String.format( "Task %s encountered an exception", this ), t ); + } + + try + { + Thread.sleep( period ); + } catch ( InterruptedException ex ) + { + Thread.currentThread().interrupt(); + } + } + + sched.cancel( this ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeThreadPool.java b/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeThreadPool.java deleted file mode 100644 index 9b2e3757..00000000 --- a/proxy/src/main/java/net/md_5/bungee/scheduler/BungeeThreadPool.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.md_5.bungee.scheduler; - -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import net.md_5.bungee.api.ProxyServer; - -public class BungeeThreadPool extends ScheduledThreadPoolExecutor -{ - - public BungeeThreadPool(ThreadFactory threadFactory) - { - super( Integer.MAX_VALUE, threadFactory ); - setKeepAliveTime( 5, TimeUnit.MINUTES ); - allowCoreThreadTimeOut( true ); - } - - @Override - protected void afterExecute(Runnable r, Throwable t) - { - super.afterExecute( r, t ); - if ( t != null ) - { - ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Task caused exception whilst running", t ); - } - } -}