2014-10-17 4 views
-1

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

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

Итак, в примере у нас есть метод, который вызывается при нажатии кнопки. Он принимает два числа и передает их во второй метод, который объединяет их и возвращает результат. Это кажется прямым. Но представьте, что мы хотели сделать еще один расчет, используя тот же метод, но мы не хотели дождаться завершения первого вычисления. Мы могли бы вызвать метод, который добавляет числа в отдельный поток, чтобы он не поддерживал поток пользовательского интерфейса. Круто. Хорошо, но что, если мы сделаем это дважды? или три раза?

То, что я пытаюсь спросить, - это когда «doSum» вызывается в первый раз под номерами, переданными в него, равными 10 и 20. Код запускает метод в отдельном потоке и должен возвращать ответ 30. Второй время, которое называется числом, составляет 30 и 50, а результат должен быть равен 80. Если по какой-то причине расчет в первом потоке продолжался, он перезаписывается, когда я вызываю тот же метод во второй раз? Повлияет ли когда-либо на риск быть возвращенным как 80 или 140?

Это имеет смысл для всех?

public void onbuttonclicked(View v) { 

int number1; 
int number2; 
int result1, result2, result3; 


//first callculation -------------------------------------- 
number1 = 10; 
number2 = 20; 
    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
     result1 = doSum(number1, number2); 
      } 
    }); 
    t1.start(); 


//second callculation ----------------------------------- 
number1 = 30; 
number2 = 50; 
    Thread t2 = new Thread(new Runnable() { 
     public void run() { 
     result2 = doSum(number1, number2); 
      } 
    }); 
    t2.start(); 

//third callculation ----------------------------------------- 
number1 = 60; 
number2 = 80; 
    Thread t3 = new Thread(new Runnable() { 
     public void run() { 
     result3 = doSum(number1, number2); 
      } 
    }); 
    t3.start(); 


} 


public static int doSum(int a, int b) 
{ 
    int result = a + b; 
    return result; 
} 
+1

Переменные number1, number2 и number3 должны быть * final *. Содержит ли ваш код? – TheLostMind

+0

или переместить их в класс – minghua

ответ

3

В первую очередь следует знать две вещи.

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

  2. Вы должны (как правило) беспокоиться о безопасности потоков/помех, когда у вас есть общий ресурс, который изменяется обоими потоками.

PS: Ваш doSum() делает очень немного обработки. Разумный JVM может на самом деле inline метод.

+1

Спасибо - отличный ответ и действительно оценен. – Regnodulous

+1

Что касается 2, вы также должны беспокоиться, если один поток изменяет число (поток gui в этом вопросе), а другие потоки используют номер. Цифры, переданные в doSum(), уже подлежат условию гонки. – minghua

+0

@minghua - Я не думаю, что его код будет компилироваться. Переменные должны быть * final *. В его кодексе нет условия гонки. – TheLostMind

0

В этом случае нет проблем с doSum(). Он использует только переданные параметры и локальные вары. Таким образом, doSum() имеет:

1) Код. Коды двоичных команд являются потокобезопасными, если они не модифицируются, (никогда не делайте этого!).

2) Локальные вары и параметры. На большинстве архитектур это означает хранение регистров и стека. Поскольку каждый поток имеет свой собственный набор регистров и стек, конфликт не может быть.

+0

Хорошо - здесь, кажется, немного спорят. Мартин - как человек с наибольшей отдачей, я предполагаю, что я собираюсь пойти с вами, и вы, похоже, согласны с мистером TheLostMind (первый ответ) правильно? Я думал о сценарии, где вы могли бы назвать функцию для ping нескольких IP-адресов. Очевидно, что время отклика может быть изменено, но пока переменные сохраняются локально, вы должны иметь возможность вызывать один и тот же метод для разных потоков для ping нескольких IP-адресов, если они не мешают друг другу? – Regnodulous

+0

@Regnodulous, просто добавьте 100 мс задержки до вызова doSum() в вашем t1. Вы увидите, будет ли это 30, 80 или 140. – minghua

+0

try {Thread.sleep (100);} catch (InterruptedException e) {} – minghua

0

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

Случайно это означает, что ваш t1 может вызвать doSum() в точке сразу после number1 = 30, таким образом, результат будет равен 50. Это всего лишь один пример.

+0

Нет гонки в doSum(). –

+0

Когда они достигают вызывающих точек doSum(), переданные аргументы будут случайными. Это гонка между тремя нитями и основной нитью. – minghua

0

Темы в java run независимые, т.е. зависит от того, как вы настраиваете. Когда потоки попадают в картину, результат всегда становится непредсказуемым, означает результат, который вы получили в первую очередь, он не попадет во второй раз.

В вашем случае onbuttonclicked() будет обрабатываться/запускаться по основному потоку, который будет создавать другие 3 потока. Его полностью до ThreadScheduler, этот поток будет работать первым. Поскольку эта операция происходит очень быстро, значит, процесс инициализации (не всегда) заканчивается.

Итак, первая нить может получить результат как 140. Его непредсказуемость.

Надеюсь, это поможет вам.

Смежные вопросы