#java #multithreading
#java #многопоточность
Вопрос:
Укажите список целых чисел (положительных и отрицательных), хранящихся в массиве. Как мне проверить, являются ли числа положительными, отрицательными или равными нулю одновременно.
Я подумал о некоторых возможных способах решения этой проблемы:
- наличие трех разных методов, которые будут вызываться, образуют три разных потока, используя
wait
иnotify
. (работает в некоторой степени) - наличие одного
synchronized
метода и трех разных потоков, обращающихся к нему с помощью глобального счетчика. Потоки взаимодействуют друг с другом. (работает в некоторой степени) - Предоставление массива в виде фрагментов потокам. Например, поток 1 будет работать с половиной элементов, а поток 2 — с другой половиной. (еще не реализовано, не уверен, что этот подход соответствует определению concurrent правильно).
Пожалуйста, имейте в виду, что это было дано в качестве задания колледжа.
Если бы кто-нибудь дал некоторые идеи или мысли о способах решения этой проблемы, было бы очень полезно.
Редактировать:
Это был точный вопрос. Я попытался немного упростить и приблизиться к нему.
Напишите Java-программу, которая сначала генерирует набор случайных чисел, а затем определяет отрицательные, положительные четные и положительные нечетные числа одновременно.
Комментарии:
1. 3-й — лучший подход.
2. @Amongalen Я тоже об этом думал. Но соответствует ли это определению «одновременно»?
3. Разрешено ли вам использовать либо
ConcurrentQueue
илиExecutor
?4. @chrylis-осторожно оптимистично — Нет, это проблема
5. Если вы хотите получить дополнительную фантазию с подходом 3, попробуйте реализовать это с помощью a
ForkJoinPool
, который, по сути, специально разработан для этого. Однако я нахожу кодирование очень неинтуитивным, поэтому я предлагаю попробовать его только после завершения фактического назначения.
Ответ №1:
Чтобы объяснить это просто:
- Этот подход обычно хорош, когда потоки выполняют различную работу, которая зависит друг от друга. Например, один поток создает некоторые данные, а другой их использует.
synchronized
используется для обеспечения того, чтобы только один поток одновременно мог выполнять определенный метод. Обычно используется для доступа к некоторым данным, которые должны быть общими. Например, несколько потоков выполняют свою работу, но затем необходимо обновить какой-то счетчик или что-то в этом роде. Это обновление должно быть синхронизировано.- Делая это, вы гарантируете, что каждый поток имеет свои собственные данные для работы с ним и не должен взаимодействовать с другими потоками. Из-за этого больше времени обработки тратится на выполнение фактической работы и меньше на обмен данными, который не может быть одновременным.
В вашей задаче вам, вероятно, следует использовать 3-й и 2-й методы. Сначала вы разделяете свои данные, обрабатываете их, а затем синхронизированным методом добавляете конечный результат к некоторому счетчику (если только это не делается в совершенно отдельном потоке после того, как все сделано).
Комментарии:
1. Спасибо. Я попробую этот подход.
Ответ №2:
Использование parallelStream
Хотя технически это не использует явные потоки, под капотом используется несколько потоков. Это одновременно. Добавляйте / удаляйте счетчики и просматривайте логику в соответствии с вашими требованиями.
Попробуйте, если хотите
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ConcurrentCounter {
public static void main(String[] args) {
final int n = 100;
final int half = n / 2;
final Random random = new Random();
// generate random numbers (use IntStream rather than Random.int(n) to control range to test
// other generating zero will be difficult. else explicitly add zeros
List<Integer> numbers = IntStream.range(0, n)
.map(i -> random.nextInt(n) - half).boxed().collect(Collectors.toList());
System.out.println(numbers);
// two counters for -ve, ve (zero can be counted as total - (-ve ve)
AtomicInteger positive = new AtomicInteger(0);
AtomicInteger negative = new AtomicInteger(0);
// multithreaded using ForkJoin Pool - beware this can be less performant
numbers.parallelStream().peek(i -> {
if (i < 0) {
negative.incrementAndGet();
} else if (i > 0) {
positive.incrementAndGet();
}
}).count(); // do not remove this dummy count(), otherwise this will not be executed as this statement will be come no-op
int zero = n - (positive.get() negative.get());
System.out.println("Negative: " negative.get() ", Zero: " zero ", Positive: " positive.get());
}
}