Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Количество повторений потоков 
V
    Опции темы
Pawl
Дата 19.2.2013, 09:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Доброго времени суток.
Создал такое приложеньице
Код

public class CheesyCounter {
    private volatile int value;

    public int getValue() {
        return value;
    }

    public synchronized void increment() {
        value++;
    }
}
Код

public class RunnerInc implements Runnable {
    private CheesyCounter counter;

    public RunnerInc(CheesyCounter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        int count = 0;
        while (counter.getValue() < 1500) {
            count++;
            counter.increment();
        }
        System.out.println(count);
    }
}
Код

public class Main {
    public static void main(String ...args) {
        CheesyCounter counter = new CheesyCounter();
        RunnerInc run = new RunnerInc(counter);
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }
}

где цикл в методе run класса RunnerInc повторяется, пока value в классе CheesyCounter не станет равно 1500. Т. е. count в run должен стать в итоге равным 1500. Так и получается, если в Main запустить один поток. Но если потоков несколько, вывод может быть, к примеру, таким:
Код

1002
0
499

т. е. суммарный count всех потоков равен 1501. Я так понимаю, что дело тут в операторе count++, но как его переписать нужным образом, не знаю. Был бы благодарен, если просветите.
Спасибо!



--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
jk1
Дата 19.2.2013, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Проблема в том, что тут должна быть атомарной операция "проверить, что счетчик меньше и увеличить его".
Вы же сделали атомарной только операцию увеличения счетчика. В итоге имеем такую последовательность:


... value = 1499

1. Thread 1 проверяет, что 1499 < 1500
2. Thread 2 проверяет, что 1499 < 1500
3. Thread 1 входит в synchronized-блок, увеличивает value на единицу и выходит
3. Thread 2 входит в synchronized-блок, увеличивает value на единицу и выходит

итого value = 1501

В качестве решения предлагаю выкинуть CheesyCounter и воспользоваться стандартным CAS'ом:

Код

public class Main {
    public static void main(String ...args) {
        AtomicInteger counter = new AtomicInteger();
        RunnerInc run = new RunnerInc(counter);
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }
}

class RunnerInc implements Runnable {
    private AtomicInteger counter;

    public RunnerInc(AtomicInteger counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while (true) {
            int value = counter.get();
            if (value < 1500000){
                counter.compareAndSet(value, value + 1);
            } else {
                break;
            }
        }
        System.out.println(counter.get());
    }
}



--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Pawl
Дата 19.2.2013, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Цитата(jk1 @  19.2.2013,  16:26 Найти цитируемый пост)
В качестве решения предлагаю выкинуть CheesyCounter и воспользоваться стандартным CAS'ом:

Спасибо за стандартное решение, просто хотелось сделать простенькие примерчики работы потоков с общим классом.


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
jk1
Дата 19.2.2013, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

хотелось сделать простенькие примерчики работы потоков с общим классом


Чтобы получился пример можно исправить и исходный вариант:

Код

public class Main {
    public static void main(String... args) {
        CheesyCounter counter = new CheesyCounter();
        RunnerInc run = new RunnerInc(counter);
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();

    }
}

class RunnerInc implements Runnable {
    private final CheesyCounter counter;

    public RunnerInc(CheesyCounter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (counter) {
                if (counter.getValue() < 150000) {
                    counter.increment();
                } else {
                    break;
                }
            }
        }
        System.out.println(counter.getValue());
    }
}

class CheesyCounter {
    private volatile int value;

    public int getValue() {
        return value;
    }

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



--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Pawl
Дата 19.2.2013, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Цитата(jk1 @  19.2.2013,  17:43 Найти цитируемый пост)
Чтобы получился пример можно исправить и исходный вариант:
 

Действительно, про синхронизацию в run я  как-то не подумал!


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
Viroman
Дата 27.2.2013, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 140
Регистрация: 28.7.2008

Репутация: нет
Всего: нет



Тема уже неактуальна, но это решение
Код

    @Override
    public void run() {
        while (true) {
            synchronized (counter) {
                if (counter.getValue() < 150000) {
                    counter.increment();
                } else {
                    break;
                }
            }
        }
        System.out.println(counter.getValue());
    }

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

Код

    public int getValue() {
        return value;
    }
переделать в
    public synchronized int getValue() {
        return value;
    }


либо вовсе заблокировать и чтение и запись на одном атомарном доступе.

Код

    public int getValue() {
        return value;
    }
    public synchronized void increment() {
        value++;
    }
переделать в 

    public int getValue() {
      synchronized(this) {
        return value;
      }
    }
    public void increment() {
      synchronized(this) {
        value++;
     }
    }

PM MAIL   Вверх
jk1
Дата 27.2.2013, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

Приведёт к тому, что лишь один поток будет накручивать счётчик, который первым зашел в синхронизированный блок. Это ли то, что хотелось достичь, вот в чём вопрос..


Viroman, а проверить?)

Модифицируем немного решение и видим ID разных потоков, которые накручивают счетчик:
Код

public class Main {
    public static void main(String... args) {
        CheesyCounter counter = new CheesyCounter();
        RunnerInc run = new RunnerInc(counter);
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }
}
class RunnerInc implements Runnable {
    private final CheesyCounter counter;
    public RunnerInc(CheesyCounter counter) {
        this.counter = counter;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (counter) {
                if (counter.getValue() < 150000) {
                    counter.increment();
                } else {
                    break;
                }
            }
        }
        System.out.println(counter.getValue());
    }
}
class CheesyCounter {
    private volatile int value;
    public int getValue() {
        return value;
    }
    public synchronized void increment() {
        value++;
        System.out.println(Thread.currentThread().getId());
    }
}



--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0824 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.