Написание Java-программы, которая использует потоки для вычисления выражения, которое игнорирует порядок операций? - PullRequest
0 голосов
/ 07 октября 2019

Я пытаюсь создать программу на Java, которая использует потоки для вычисления выражения, такого как:

3 + 4 / 7 + 4 * 2

и выводит

Enter problem: 3 + 4 / 7 + 4 * 2
Thread-0 calculated 3+4 as 7
Thread-1 calculated 7/7 as 1
Thread-2 calculated 1+4 as 5
Thread-3 calculated 5*2 as 10
Final result: 10

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

1 Ответ

2 голосов
/ 07 октября 2019

Мой честный, профессиональный совет: не пытайтесь использовать многопоточность для этой проблемы.

Научитесь сначала писать понятный, надежный однопоточный код. Узнайте, как его отладить. Узнайте, как написать одно и то же разными способами. Только тогда вы можете начать вводить огромную сложность, которая является многопоточностью, и иметь все шансы, что она будет правильной.

И учиться, читая о том, как правильно писать многопоточный кодКакие проблемы выигрывают от многопоточности. Эта проблема не возникает, потому что вам нужен результат предыдущей арифметической операции в качестве входных данных для следующего.

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

Держите изменяемое состояние как можно жестче под контролем. Создайте Runnable подкласс, который содержит операцию, которую вы собираетесь выполнить:

class Op implements Runnable {
  final int operand1, operand2;
  final char oprator;

  int result;

  Op(int operand1, char oprator, int operand2) {
    // Initialize fields.
  }

  @Override public void run() {
    result = /* code to calculate `operand1 (oprator) operand2` */;
  }
}

Теперь вы можете вычислить, скажем, 1 + 2, используя:

Op op = new Op(1, '+', 2);
Thread t = new Thread(op);
t.start();
t.join();
int result = op.result;

(Или,вы могли бы просто использовать int result = 1 + 2; ...)

Так что теперь вы можете использовать это в цикле:

String[] tokens = eqn.split(" ");
int result = Integer.parseInt(tokens[0]);
for (int t = 1; t < tokens.length; t += 2) {
  Op op = new Op(
      result,
      result, tokens[t].charAt(0), 
      Integer.parseInt(tokens[t+1]));
  Thread t = new Thread(op);
  t.start();
  t.join();    
  result = op.result;
}

Все изменяемое состояние ограничено областью действия op переменная. Если, скажем, вы хотите выполнить второй расчет, вам не нужно беспокоиться о том, какое предыдущее состояние все еще находится в процессе: вам не нужно ничего сбрасывать перед другим запуском;Вы можете вызывать этот код параллельно, если хотите, без помех между запусками.

Но весь этот цикл можно было бы написать более чисто - и быстрее - с помощью простого вызова метода:

for (int t = 1; t < tokens.length; t += 2) {
  result = method(
      result,
      result, tokens[t].charAt(0), 
      Integer.parseInt(tokens[t+1]));
}

, где method - метод, содержащий /* code to calculate operand1 (oprator) operand2 */.

...