Счетчики одновременной загрузки в Java - PullRequest
1 голос
/ 23 февраля 2012

В рамках нашей университетской курсовой работы мы должны создать многопоточный сервер загрузки на Java. Все работает гладко, не считая одного бита: сервер должен показывать общее количество загрузок для каждого элемента при каждой загрузке. Пока что я заставил его работать, если оба клиента не запросят его одновременно. Код ниже: если у кого-то есть какие-либо иды, я был бы очень признателен. Также мы должны включить часть thread.sleep и увеличить счетчик таким сложным образом.

//Snipper from Protocol.java

if (theInput.equals("1")) {

            theOutput = "The program displays a message... Another? Y or N";


            DownloadCounter counter = new DownloadCounter();

            count = DownloadCounter.getcount();//count is a var in Protocol.java it is                      static

            int tmp = count;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                System.out.println("sleep interrupted");
            }
            count = tmp + 1;

            DownloadCounter.setcount(count);

            System.out.println("Download Total " + count);


            state = ANOTHER;

DownloadCounter:

//DownloadCounter.java
public class DownloadCounter {

    private static int count;

    public static synchronized int getcount(){
        return count;
    }

    public static synchronized void setcount(int num){
        DownloadCounter.count = num;
    }
}

Ответы [ 3 ]

3 голосов
/ 23 февраля 2012

Основная проблема заключается в том, что у вас есть два потока, которые выполняют get, increment и set, поэтому рассмотрим следующую ситуацию:

Thread 1: set(5) // now count is 5
Thread 1: get() // Thread 1 gets 5
Thread 2: get() // Thread 2 gets 5
Thread 2: increments its local copy of count to 6
Thread 1: increments its local copy of count to 6
Thread 2: set(6) // now the count is 6
Thread 1: set(6) // the count is still 6, but it should be 7!!!

Решение состоит в том, чтобы реализовать метод приращения, который увеличивает счетчик потокобезопасным способом:

public synchronized void increment()
{
    count++;
}

Вы также можете использовать AtomicInteger и избежать блокировки:

AtomicInteger count = new AtomicInteger(0);

public int getCount()
{
    return count.get();
}

public void increment()
{
    count.incrementAndGet();
}

Вы также заявили, что счетчик должен подсчитывать количество загрузок для каждого элемента, однако ваш текущий код этого не сделает. Ваш текущий счетчик будет подсчитывать ВСЕ загрузки для ВСЕХ предметов. Подсказка: вы делаете все в DownloadCounter статично, и это не будет работать хорошо, если вы хотите иметь отдельный счетчик для каждого элемента.

0 голосов
/ 23 февраля 2012

Ключ к правильному выполнению - именно к тому, чтобы получить / увеличить / установить атомарную операцию. Вместо метода setCount должен использоваться синхронизированный метод incrementCount().

Вы также можете полностью избежать синхронизации, используя AtomicInteger и используя его метод incrementAndGet() внутри метода incrementCount().

Обратите внимание, что инструкция DownloadCounter counter = new DownloadCounter(); совершенно не нужна. Класс должен иметь закрытый конструктор, чтобы предотвратить такие ненужные реализации.

0 голосов
/ 23 февраля 2012

DownloadCounter нужен метод для увеличения. Нет безопасного способа увеличить счетчик только с помощью методов getCount и setCount.

В Java есть класс AtomicInteger для обработки вещей такого типа.

Также вы вызываете только статические методы в DownloadCounter, поэтому нет необходимости создавать новый экземпляр.

...