2017-07-16 97 views
0

由於實現了重新啓動機制,我正面臨使用ScheduledExecutorService的錯誤行爲。ScheduledExecutorService Thread創建多個線程

問題 - 短

每次重新啓動嘗試創建一個新的計劃任務,然後重新啓動舊的。

問題 - 龍

過程的目標是發佈消息到RabbitMQ的不時(這是保活)。當RabbitMQ發生異常時,它使用ExceptionObserver通知 發生異常。實現的ExceptionObserver會停止服務並重新啓動它。它試圖重啓3次,如果重啓成功,計數爲 重置爲零。如果無法重新啓動,則嘗試計數會遞增,如果達到嘗試限制,則會關閉該過程。

每次服務重新啓動時,它都會創建一個新的「KeepAliveService」並重新啓動最後的服務。因此,每次發生異常時,都會創建一項新服務,並重新啓動舊的服務。如果重啓後有1次異常,則有2個進程正在運行。如果2個異常事件有3個進程正在運行,依此類推。

服務類處理保持連接服務(啓動/停止ScheduledExecutorService的)

private KeepaliveExecutor keepaliveExecutor; // This is the runnable used inside the scheduledService 
private ScheduledFuture futureTask; // The escheduled task 
private ScheduledExecutorService scheduledService; // the scheduled service 
private ExceptionObserver exceptionObserver; // The Exception Handler, which will handle the exceptions 

public void startService(final int keepaliveTime) throws IllegalArgumentException, FInfraException { 
    keepaliveExecutor = new KeepaliveExecutor(new RabbitMQService(settings), settings); 
    keepaliveExecutor.setExceptionObserver(exceptionObserver); 
    scheduledService = Executors.newSingleThreadScheduledExecutor(); 
    futureTask = scheduledService.scheduleAtFixedRate(keepaliveExecutor, 0, keepaliveTime, TimeUnit.MINUTES); 
} 

public void stopService() { 
    futureTask.cancel(true); 
    scheduledService.shutdown(); 
} 

的KeepaliveExecutor類

class KeepaliveExecutor implements Runnable { 

private FInfraExceptionObserver exceptionObserver; 

@Override 
public void run() { 
    try { 
     final String keepAlive = JsonMapper.toJsonString(keepaliveMessage); 
     rabbitService.publishMessage(keepAlive); 
     keepaliveMessage.setFirtsPackage(false); 
    } catch(FInfraException ex) { 
     if(exceptionObserver != null) { 
      exceptionObserver.notifyExpcetion(ex); 
     } 
    }   
} 

的ExceptionObserver實現類

public class FInfraExceptionHandler implements FInfraExceptionObserver { 

private final FInfraServiceHandler finfraHandler; 

public FInfraExceptionHandler(FInfraServiceHandler finfraHandler) { 
    this.finfraHandler = finfraHandler; 
} 

@Override 
public void notifyExpcetion(Throwable ex) { 
    Util.logger.log(Level.INFO, "F-Infra Exception occurred", ex); 
    finfraHandler.stopService(); 
    Util.logger.log(Level.INFO, "Waiting 30s for restarting..."); 
    Util.wait(30, TimeUnit.SECONDS); 
    finfraHandler.startService(); 
} 

的FInfraServiceHandler

public class FInfraServiceHandler { 

private static final int ATTEMPT_LIMIT = 3; 

private FInfraService finfraService; 
private int keepaliveTime; 
private int attempt; 

public FInfraServiceHandler() { 
    this.finfraService = new FInfraService(); 
    this.finfraService.setExceptionObserver(new FInfraExceptionHandler(this)); 
    this.attempt = 0; 
} 

void startService(){ 
    if(attempt <= ATTEMPT_LIMIT) { 
     try { 
      attempt++; 
      Util.logger.log(Level.INFO, "Starting F-Infra Service. Attemp[{0} of {1}]", new String[]{String.valueOf(attempt), String.valueOf(ATTEMPT_LIMIT)}); 
      finfraService.startService(keepaliveTime); 
     } catch(FInfraException | RuntimeException ex){ 
      Util.logger.log(Level.INFO, "F-INFRA EXCEPTION", ex); 
      startService(); 
     } 
     Util.logger.log(Level.INFO, "F-Infra started!"); 
     attempt = 0; 
     return; 
    } 
    Util.logger.log(Level.INFO, "Restart attemp limit reached."); 
    Main.closeAll(new ShutdownException("It's not possible stablish a connection with F-Infra Service.")); 
} 

public void stopService() { 
    if(attempt > 0){ 
     Util.logger.log(Level.INFO, "Stpoping F-Infra..."); 
     finfraService.stopService(); 
    } 
} 

這裏如下這告訴我有運行

jul 16, 2017 2:58:03 PM domain.FInfraServiceHandler startService 
INFO: Starting F-Infra Service. Attemp[1 of 3] 
jul 16, 2017 2:58:03 PM domain.FInfraServiceHandler startService 
INFO: F-Infra started! 
jul 16, 2017 5:01:15 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: F-Infra Exception occurred 
domain.FInfraException: java.net.UnknownHostException: rabbit.domain 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:48) 
     at domain.RabbitMQService.publishMessage(RabbitMQService.java:66) 
     at domain.KeepaliveExecutor.run(KeepaliveExecutor.java:38) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) 
     at java.util.concurrent.FutureTask.runAndReset(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
     at java.lang.Thread.run(Unknown Source) 
Caused by: java.net.UnknownHostException: rabbit.domain 
     at java.net.AbstractPlainSocketImpl.connect(Unknown Source) 
     at java.net.PlainSocketImpl.connect(Unknown Source) 
     at java.net.SocksSocketImpl.connect(Unknown Source) 
     at java.net.Socket.connect(Unknown Source) 
     at com.rabbitmq.client.impl.FrameHandlerFactory.create(FrameHandlerFactory.java:32) 
     at com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory.newConnection(RecoveryAwareAMQConnectionFactory.java:34) 
     at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.init(AutorecoveringConnection.java:91) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:670) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:722) 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:45) 
     ... 9 more 

jul 16, 2017 5:01:15 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: Waiting 30s for restarting... 
jul 16, 2017 5:01:45 PM domain.FInfraServiceHandler startService 
INFO: Starting F-Infra Service. Attemp[1 of 3] 
jul 16, 2017 5:01:45 PM domain.FInfraServiceHandler startService 
INFO: F-Infra started! 
jul 16, 2017 6:01:58 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: F-Infra Exception occurred 
domain.FInfraException: java.net.UnknownHostException: rabbit.domain 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:48) 
     at domain.RabbitMQService.publishMessage(RabbitMQService.java:66) 
     at domain.KeepaliveExecutor.run(KeepaliveExecutor.java:38) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) 
     at java.util.concurrent.FutureTask.runAndReset(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
     at java.lang.Thread.run(Unknown Source) 
Caused by: java.net.UnknownHostException: rabbit.domain 
     at java.net.AbstractPlainSocketImpl.connect(Unknown Source) 
     at java.net.PlainSocketImpl.connect(Unknown Source) 
     at java.net.SocksSocketImpl.connect(Unknown Source) 
     at java.net.Socket.connect(Unknown Source) 
     at com.rabbitmq.client.impl.FrameHandlerFactory.create(FrameHandlerFactory.java:32) 
     at com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory.newConnection(RecoveryAwareAMQConnectionFactory.java:34) 
     at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.init(AutorecoveringConnection.java:91) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:670) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:722) 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:45) 
     ... 9 more 

jul 16, 2017 6:01:58 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: Waiting 30s for restarting... 
jul 16, 2017 6:02:03 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: F-Infra Exception occurred 
domain.FInfraException: java.net.UnknownHostException: rabbit.domain 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:48) 
     at domain.RabbitMQService.publishMessage(RabbitMQService.java:66) 
     at domain.KeepaliveExecutor.run(KeepaliveExecutor.java:38) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) 
     at java.util.concurrent.FutureTask.runAndReset(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
     at java.lang.Thread.run(Unknown Source) 
Caused by: java.net.UnknownHostException: rabbit.domain 
     at java.net.AbstractPlainSocketImpl.connect(Unknown Source) 
     at java.net.PlainSocketImpl.connect(Unknown Source) 
     at java.net.SocksSocketImpl.connect(Unknown Source) 
     at java.net.Socket.connect(Unknown Source) 
     at com.rabbitmq.client.impl.FrameHandlerFactory.create(FrameHandlerFactory.java:32) 
     at com.rabbitmq.client.impl.recovery.RecoveryAwareAMQConnectionFactory.newConnection(RecoveryAwareAMQConnectionFactory.java:34) 
     at com.rabbitmq.client.impl.recovery.AutorecoveringConnection.init(AutorecoveringConnection.java:91) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:670) 
     at com.rabbitmq.client.ConnectionFactory.newConnection(ConnectionFactory.java:722) 
     at domain.RabbitMQService.openConnection(RabbitMQService.java:45) 
     ... 9 more 

jul 16, 2017 6:02:03 PM domain.FInfraExceptionHandler notifyExpcetion 
INFO: Waiting 30s for restarting... 
jul 16, 2017 6:02:28 PM domain.FInfraServiceHandler startService 
INFO: Starting F-Infra Service. Attemp[1 of 3] 
jul 16, 2017 6:02:28 PM domain.FInfraServiceHandler startService 
INFO: F-Infra started! 
jul 16, 2017 6:02:33 PM domain.FInfraServiceHandler startService 
INFO: Starting F-Infra Service. Attemp[1 of 3] 
jul 16, 2017 6:02:33 PM domain.FInfraServiceHandler startService 
INFO: F-Infra started! 

我不知道該怎麼辦,關閉舊線,或者使用當前的重新啓動多個服務日誌。我嘗試過的很多方法都是調用Thread.currentThread()。interrupt();在調用start方法之前調用ExceptionObserver類。 但這並不奏效。

我不知道該怎麼做。

回答

2

FInfraServiceHandler類中,如果attempt爲零,則stopService方法不會執行任何操作。

public void stopService() { 
    if(attempt > 0){ 
     Util.logger.log(Level.INFO, "Stpoping F-Infra..."); 
     finfraService.stopService(); 
    } 
} 

所以原來的ScheduledExecutorService繼續前進。當我刪除條件時,代碼表現良好。

請注意,順便說一下,您在同一實例上從不同的線程調用startServicestopService。我想你需要在可變字段attempt上進行某種同步。

相關問題