механизм синхронизации Java

#java #synchronization

#java #синхронизация

Вопрос:

Веб-приложение запрашивает внешний сервер. Если более 80% запросов к серверу, отправленных в течение последних ‘n’ минут, завершаются неудачей, то веб-приложению следует отказаться от запроса к серверу и выполнить другую логику. Я мог бы подумать об атомарном целом числе, увеличиваемом неудачными запросами. Но я не думаю, что atomic integer поддерживает какое-либо действие, которое должно быть выполнено, если значение atomic integer достигает определенного значения. Есть ли какой-нибудь более разумный способ сделать это на java?

Комментарии:

1. Насколько вы привязаны к этому точному 80%-му ограничению? Это всего лишь некоторая эвристика для того, когда прекратить сокращать ваши потери?

2. Не совсем. В идеале это должно быть 100%. я не хочу нагружать внешний сервер, когда он не отвечает..

Ответ №1:

Что ж, после обновления вашего атомарного целого числа вы могли бы проверить его значение, и если выполнено 80%, тогда вы могли бы предпринять действия (например, пометить этот сервер как «слабо отвечающий или около того»). Если вы работаете в многопоточной среде, в вашем решении нет ничего плохого.

Другое решение состоит в том, чтобы потоки вызывали синхронизированный метод для увеличения неатомного целого числа и выполнения проверки. Это целое число должно было бы быть атрибутом класса, к которому принадлежит этот метод.

Ответ №2:

Если вы хотите отслеживать события за последние ‘N’ минут, вам нужно больше, чем просто целое число. Вам нужно знать, что происходило ‘N’ минут назад, чтобы вы могли правильно оценить уровень успеха.

Вот один из способов сделать это:

 import java.util.LinkedList;

/**
 * Class that monitors outcomes for until the proportion of successes in a
 * specified time window falls below a trigger level, at which point an action
 * is invoked.
 * 
 * @author Simon
 */
public class SuccessMonitor {
    /** An outcome */
    static class Outcome {
        /** Time of outcome */
        final long eventTime = System.currentTimeMillis();

        /** True for success, false for failure */
        boolean outcome;
    }

    /** The action to invoke when there are two few successes */
    private final Runnable action_;

    /** The history of outcomes in the time window */
    private final LinkedList<Outcome> events_ = new LinkedList<Outcome>();

    /** Number of successes in the time window */
    private int goodCount_ = 0;

    /** Synchronization lock */
    private final Object lock_ = new Object();

    /** Length of the time window in milliseconds */
    private final long trackTime_;

    /** The success proportion at which to invoke the action */
    private final double triggerLevel_;


    /**
     * New monitor
     * 
     * @param trackTime
     *            number of milliseconds to retain history for
     * @param triggerLevel
     *            the level at which to invoke the action
     * @param action
     *            the action
     */
    public SuccessMonitor(long trackTime, double triggerLevel, Runnable action) {
        trackTime_ = trackTime;
        triggerLevel_ = triggerLevel;
        action_ = action;
    }


    private void check(boolean result) {
        // create a new outcome
        Outcome out = new Outcome();
        out.outcome = resu<

        double level;
        synchronized (lock_) {
            // add the new outcome
            goodCount_  = (result) ? 1 : 0;
            events_.addLast(out);

            // remove expired outcomes
            long expire = System.currentTimeMillis() - trackTime_;
            while( (!events_.isEmpty())
                    amp;amp; (events_.getFirst().eventTime < expire) ) {
                out = events_.removeFirst();
                goodCount_ -= (out.outcome) ? 1 : 0;
            }

            // Calculate the success level.
            if (events_.isEmpty()) {
                // if empty assume ok
                level = 1.0;
            } else {
                // calculate success level
                level = (double) goodCount_ / events_.size();
            }
        }

        // if level has fallen too low, invoke action
        if (level < triggerLevel_) action_.run();
    }


    /**
     * Notify this monitor of a failure.
     */
    public void fail() {
        check(false);
    }


    /**
     * Reset this monitor, causing it to discard all currently stored history.
     */
    public void reset() {
        synchronized (lock_) {
            events_.clear();
            goodCount_ = 0;
        }
    }


    /**
     * Notify this monitor of a success.
     */
    public void success() {
        check(true);
    }
}