2016-12-02 3 views
-4
package newpackage; 

import java.util.logging.Level; 
import java.util.logging.Logger; 

class test { 

    public int in = 0; 

    void helper() { 

     Thread t1 = new Thread(
       () 
       -> { 

      add(); 

     } 
     ); 

     Thread t2 = new Thread(
       () 
       -> { 

      add(); 

     } 
     ); 
     t1.start(); 
     t2.start(); 
     try { 
      t1.join(); 
      t2.join(); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(test.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    void add() { 
     for (int i = 0; i < 40; i++) { 
      in += i; 
      try { 
       Thread.sleep(50); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(test.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 
    } 

} 

public class Main { 

    public static void main(String[] args) { 
     test a = new test(); 
     a.helper(); 
     System.out.println(a.in); 
    } 
} 

То, что я хочу, - это запустить один и тот же метод из разных потоков одновременно.Многопоточность по одному и тому же методу в java

Но приведенный выше код не дает правильного результата. Он дает выход меньше 1560 (780 + 780). Как я могу это достичь?

Заранее спасибо.

+2

«Правильный результат», каков ваш ожидаемый результат и каков ваш наблюдаемый результат? Кроме того, ваш метод ничего не делает - пожалуйста, напишите реальный код, код, который мы можем скомпилировать, протестировать и изменить. –

+4

«не дает правильного результата». Я полагаю, вы имеете в виду, что он не дает ожидаемого результата, потому что он определенно делает то, что говорит спецификация Java. Как вы думаете, что он должен делать, что он делает? –

+0

@AndyTurner извините. я сделал это ради простоты. теперь отредактирован. –

ответ

1

Вы столкнулись с одной из классических проблем параллельных программ. Mutable shared state без надлежащей синхронизации. Ваша переменная in изменяется обоими потоками одновременно, и, кроме того, операция i += 1 не является атомарной. На самом деле то, что происходит это:

int temp = i + 1; 
i = temp; 

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

// assuming i == 3 
int temp = i + 1; // Thread 1, temp == 4 
int temp = i + 1; // Thread 2, temp == 4 
i = temp; // Thread 2, i == 4 
i = temp; // Thread 1, i == 4 

Как вы можете видеть, что мы увеличивается в два раза, но я должен только повышается на 1. Более того, поскольку ваша переменная не является изменчивой или что-либо еще не имеет видимости для всех потоков, это означает, что если Thread 1 изменяет переменную, JVM не гарантирует, что это изменение будет видимым для любого другого потока, читающего переменную.

Для правильной работы вам понадобится какая-то помощь по синхронизации, самым простым будет блок synchronized. Однако в этом случае это приведет к сбою в попытке добавить вещи параллельно, поскольку синхронизация заставит все работать эффективно последовательно, с некоторыми накладными расходами.

Если вы действительно хотите добавить что-то параллельно, посмотрите на Java 8 Streams или Fork-Join Framework в Java 7. Обратите внимание, что это делается только с достаточно большим набором данных, так как параллельная работа всегда приходит с некоторыми накладными расходами.

+0

спасибо. понял . Тогда что, если моя функция add() не будет работать с одним и тем же объектом/переменной. Скажем, моя функция add() принимает параметр fileName, а затем записывает на него. Итак, если я передаю два разных имени файла одной и той же функции из разных потоков, будет ли какая-то коррупция? –

+0

Нет, запись в отдельные файлы может выполняться из разных потоков параллельно, хотя в конечном итоге это будет зависеть от базовой файловой системы. – diesieben07

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