2015-03-22 8 views
0

Я пытаюсь понять, что было бы лучшим способом исправить эту проблему с параллельным параллелизмом с помощью такого кода. Я попытался добавить блокировку вокруг «index ++», но есть ли лучший способ достижения параллелизма?Синхронизация с вложенным классом, но с глобальной переменной? (JAVA)

public class MainClass { 
     public static short index = 0; 

     public static void main(String[] args) { 
      MainClass testConc = new MainClass(); 
      Thread thr1 = new Thread(testConc.new MyRunnable()); 
      thr1.start(); 
      Thread thr2 = new Thread(testConc.new MyRunnable()); 
      thr2.start(); 
     }  

     class MyRunnable implements Runnable { 
      private static final Object lock = new Object(); 
      public void run() { 
       while (index < 99) { 
        System.out.println(index); 
        synchronized(lock) { 
         index++; 
        } 
       } 
      } 
     } 
    } 
+0

Как параллелизм «сломан»? Что вы ожидаете от вывода и что получаете? –

+0

@jas это статическое поле, так что это общий замок – Zielu

+0

@jas, объект блокировки является 'static', что означает, что он делится между всеми экземплярами. –

ответ

0

Вы должны иметь блокировку на том же уровне (MainClass), что и данные, используемые для защиты. Переменная класса index должна иметь область видимости private, потому что синхронизация происходит только в классе.

Также, как отметил Томаш в комментарии, переменная должна быть помечена как volatile, что гарантирует, что любые изменения ее значения видны для всех потоков (начиная с Java 5). Это устраняет необходимость синхронизации доступа для чтения до index. Так что исправленный код будет выглядеть примерно так:

public class MainClass { 
    private static volatile short index = 0; 
    private static final Object lock = new Object(); 
    ... 

Если вы хотите, чтобы программа для вывода индексов от 0 к 98 в порядке и только один раз в значение индекса, вам необходимо изменить метод run() в этом:

public void run() { 
    while (index < 99) { 
     synchronized (lock) {      
      // double-check for threads that made it here 
      // before #index got incremented to 99 by the thread that 
      // made the final increment 
      if (index < 99) { 
       System.out.println(index); 
       index++; 
      } 
     } 
    } 
} 

Обратите внимание, что для double-checkindex < 99 требуется, поскольку index может быть изменен другой поток после того, как значение было оценено в состоянии while. Вы увидите это, если увеличите количество потоков, которые порождаются MainClass, используя старую версию run().

+0

Переменная класса 'index' также должна быть объявлена' volatile', чтобы JVM знал, что его значение можно манипулировать разными потоками. – tzima

+0

@ TomášZíma Но можно ли коротко объявить 'volatile'? – thestranger

+0

@thestranger Да, он может. – tzima

0

AtomicInteger будет лучше, чем блокировка вокруг индекса ++ Он разработан специально для этого случая использования.

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

Кстати, я не вижу в вашем коде «проблемы с параллельным доступом».

+0

Я не могу изменить индекс от короткого ко всему. Поэтому, имея в виду, будут ли другие решения. И сломанный параллелизм - это если у меня не было «синхронизировано (блокировка)». Будет ли это работать, если я сделаю синхронизацию «run()»? – thestranger

+0

не будет работать с синхронизированным run(). Он будет «синхронизирован» run() независимо от каждого потока, поэтому синхронизации вообще не будет. С точки зрения производительности с использованием ReentrantLock лучше, чем синхронизировано (obj). Я уверен, что вы можете «изменить» индекс на что-то еще, поскольку вы уже перепутали его с вашими потоками, подумайте об этом (вы можете написать getter, который дает значение как короткое) – Zielu

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

  • Нет связанных вопросов^_^