Многопоточная Java-программа, использующая join (), дает неверные результаты при расчете суммы смежных чисел

Я написал эту простую многопоточную программу для добавления чисел от 1 до 100 000.Когда я запустил это, я получил разные значения в качестве конечного результата (значения меньше, чем ожидалось 5000050000).Когда я выполнял программу, используя только один поток, он дал правильный результат.Программа также работает для меньших значений, таких как 100. Что, возможно, пошло не так?Заранее спасибо.
4 голоса | спросил user54321 28 Mayam18 2018, 01:03:51

5 ответов


0
Несинхронизированный доступ к общему изменяемому состоянию обычно не подходит.В вашем ---- +: = 0 =: + ---- есть изменяемая переменная ---- +: = 1 =: + ---- .Когда вы запускаете темы:вы разделяете изменяемое состояние ---- +: = 3 =: + ---- между этими двумя потоками.Внутри нет никакой синхронизации ---- +: = 4 =: + ---- , поэтому потоки будут загружать память друг друга только в случайные промежутки времени.Вот рабочая версия:Выходы:Дополнительное примечание: всегда используйте ---- +: = 7 =: + ---- индексирование диапазонов.Это значительно снижает вероятность появления ошибок, связанных с ошибками.Кроме того, я заменил класс ---- +: = 8 =: + ---- методом: ничто не может пойти не так с локальными переменными внутри метода, и чем меньше изменяемое состояние, тем лучше.
ответил Andrey Tyukin 28 Mayam18 2018, 01:20:11
0
Класс ---- +: = 0 =: + ---- не является потокобезопасным, и вы используете один и тот же экземпляр в двух потоках.Таким образом, каждый поток заменяет значение, установленное другим.Простым решением будет создание двух ---- +: = 1 =: + ---- экземпляров, по одному для каждого ---- +: = 2 =: + ---- .Это классический расчет, который может быть разбит на независимые части (которые могут выполняться одновременно) и сведен к одному результату в конце.
ответил Jennifer P. 28 Mayam18 2018, 01:26:26
0
---- +: = 0 =: + ---- не является атомарным (см. Этот ответ ).У вас есть два потока, изменяющие одно и то же значение ---- +: = 1 =: + ---- одновременно, и эти два потока мешают друг другу.Взгляните на ---- +: = 2 =: + ---- ( javadoc ), у которого есть метод ---- +: = 3 =: + ----, который атомарно добавляет некоторое число:При таком подходе оба потока могут добавлять в ---- +: = 5 =: + ---- атомарно, чтобы они больше не мешали.
ответил pkpnd 28 Mayam18 2018, 01:23:15
0
это не самый простой способ достичь вашего результата.Если вы хотите вычислить сумму чисел от 1 до N, используйте следующую формулу: сумма от 1 до N = N (N + 1) /2.Вы сталкиваетесь с тем, что называется непоследовательным чтением.Ваши два потока совместно используют одно и то же поле «calc» и особенно общее длинное поле класса «Расчет».С вашим решением это может произойти:trhead1 читает итоговое значение равное 0, thread1 увеличивает значение итогового значения до 1, thread2 считывает общее значение равное 0, thread2 увеличивает значение итогового значения до 1.В вашем решении возможны другие сценарии, факт в том, что в этом случае значение total не предсказуемо. Поэтому используйте предоставленную формулу или простое для, не используйте асинхронное решение для проблемы синхронизации.
ответил GJCode 28 Mayam18 2018, 01:37:22
0
Основная проблема вашего кода заключается в том, что ---- +: = 0 =: + ---- фактически является оберткой для общей переменной (поле ---- +: = 1 =: + ----) который обновляется без какой-либо синхронизации.Есть три способа решить эту проблему:синхронизировать переменную;например, используя ---- +: = 2 =: + ---- в соответствующих точкахиспользуйте атомарный тип для переменнойне используйте переменную общего доступа.Третий вариант лучше с точки зрения производительности, а реализация проста;см. ответ @ JenniferP.Обратите внимание, что дополнительная синхронизация не требуется, если вы предоставляете каждому потоку свой собственный объект ---- +: = 3 =: + ---- .Связи, возникающие перед вызовами ---- +: = 4 =: + ---- и ---- +: = 5 =: + ----, гарантируют, что основной поток увидит правильные результатыиз дочерних потоков, когда он читает их после объединения.Для чего стоит поточно-ориентированная реализация ---- +: = 6 =: + ----, которая будет работать при совместном использовании экземпляра, будет выглядеть так:Обратите внимание, что вам нужно синхронизировать как метод получения, так и метод приращения.Альтернативой является использование ---- +: = 8 =: + ---- для представления итога.Но в обоих случаях будут значительные издержки из-за использования разделяемой переменной.(В версии с ---- +: = 9 =: + ---- издержки могут быть чрезмерными из-за конфликта блокировок. Я был бы удивлен, если бы было какое-либо ускорение по сравнению с однопоточной версией.Даже если бы вы могли устранить накладные расходы на создание потоков.)
ответил Stephen C 28 Mayam18 2018, 02:02:55

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132