Package programming5.concurrent

Source Code of programming5.concurrent.BackoffTestThread

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package programming5.concurrent;

import java.util.concurrent.TimeUnit;
import programming5.io.Debug;
import programming5.io.DebugExceptionHandler;
import programming5.io.ExceptionHandler;
import programming5.io.RobustThread;

/**
* TODO: Avoid thrashing between backoff and recover on regress (when period should be stable)
* @author andresqh
*/
public abstract class BackoffTestThread {

    public static enum BackoffStrategy {LINEAR, EXPONENTIAL};
    public static enum RecoveryStrategy {RESET, REGRESS};

    private BackoffStrategy backoffStrategy = BackoffStrategy.LINEAR;
    private RecoveryStrategy recoveryStrategy = RecoveryStrategy.RESET;

    private RobustThread testThread = null;
    private ExceptionHandler exceptionHandler = new DebugExceptionHandler();
    private long testingPeriod;
    private long basePeriod;
    private boolean active = true;

    public BackoffTestThread(long myTestingPeriod) {
        basePeriod = testingPeriod = myTestingPeriod;
    }

    public BackoffTestThread(long myTestingPeriod, TimeUnit timeUnit) {
        basePeriod = testingPeriod = TimeUtils.toMilliseconds(myTestingPeriod, timeUnit);
    }

    public final void setBackoffStrategy(BackoffStrategy strategy) {
        if (testThread == null) {   // TODO: Explore possibility of allowing the change
            backoffStrategy = strategy;
        }
        else {
            throw new IllegalStateException("BackoffTester: Cannot change strategy after thread has started");
        }
    }

    public final void setRecoveryStrategy(RecoveryStrategy strategy) {
        if (testThread == null) {   // TODO: Explore possibility of allowing the change
            recoveryStrategy = strategy;
        }
        else {
            throw new IllegalStateException("BackoffTester: Cannot change strategy after thread has started");
        }
    }

    // Note: If the exception handler is set to restart, the action when starting method will be called again
    // TODO: Separate action starting method? Putting it outside the robust thread run would violate the start() thread contract
    public final void setExceptionHandler(ExceptionHandler handler) {
        if (testThread == null) {   // TODO: Explore possibility of allowing the change
            exceptionHandler = handler;
        }
        else {
            throw new IllegalStateException("BackoffTester: Cannot change handler after thread has started");
        }
    }

    public abstract boolean test();

    public void actionWhenStarting() {}

    public void actionWhenPosTest() {}

    public void actionWhenNegTest() {}

    public void actionWhenCancelled() {}

    public final void start() {
        if (testThread == null) {
            testThread = new RobustThread(
                new Runnable() {    // First parameter of RobustThread constructor

                    @Override
                    public void run() {
                        actionWhenStarting();
                        while (active) {
                            try {
                                Thread.sleep(testingPeriod);
                                if (test()) {
                                    actionWhenPosTest();
                                    recover();
                                }
                                else {
                                    actionWhenNegTest();
                                    backoff();
                                }
                            }
                            catch (InterruptedException ie) {
                                Debug.println("BackoffThread interrupted (cancelled)", "programming5.concurrent.BackoffTestThread");
                            }
                        }
                        actionWhenCancelled();
                    }
                },
                exceptionHandler    // Second parameter of RobustThread constructor
            );
            testThread.start();
        }
        else {
            throw new IllegalStateException("BackoffTester: Already started");
        }
    }

    public final void cancel() {
        if (testThread != null) {
            active = false;
            testThread.interrupt();
        }
        else {
            throw new IllegalStateException("BackoffTester: Cannot cancel thread: Not started");
        }
    }

    private void recover() {
        switch (recoveryStrategy) {
            case RESET: testingPeriod = basePeriod;
            break;
            case REGRESS: {
                if (testingPeriod > basePeriod) {
                    switch (backoffStrategy) {
                        case LINEAR: testingPeriod -= basePeriod;
                        break;
                        case EXPONENTIAL: testingPeriod /= 2;
                        break;
                    }
                }
            }
            break;
        }
    }

    private void backoff() {
        switch (backoffStrategy) {
            case LINEAR: testingPeriod += basePeriod;
            break;
            case EXPONENTIAL: testingPeriod *= 2;
            break;
        }
    }


}
TOP

Related Classes of programming5.concurrent.BackoffTestThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.