簡體   English   中英

ScheduledExecutorService線程創建多個線程

[英]ScheduledExecutorService Thread creating multiples threads

由於實施了重啟機制,因此我使用ScheduledExecutorService遇到錯誤的行為。

問題-簡短

每次重新啟動嘗試都會創建一個新的計划任務並重新啟動舊任務。

問題-長

該過程的目標是不時將消息發布到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類上進行操作。 但這是行不通的。

我不知道該怎么辦。

FInfraServiceHandler類,你stopService如果方法不執行任何操作attempt是零。

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

因此原始的ScheduledExecutorService繼續運行。 當我刪除條件時,代碼表現良好。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM