2014-09-29 4 views
0

Быстрый (я думаю) вопрос параллелизма: я проходил курс многопоточности на Udemy.com, и учитель говорил через приведенный ниже код. Хотя он объяснил это, я все еще не уверен, почему вы создавали бы объекты lock1 и lock2, а не блокировали по list1 и list2.Синхронизация: несколько блокировок - создание объектов блокировки?

App.java:

public class App { 

    public static void main(String[] args) { 
     Worker worker = new Worker(); 
     worker.main(); 
    } 
} 

Worker.java:

import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 


public class Worker { 

    private Random random = new Random(); 

    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 

    private List<Integer> list1 = new ArrayList<Integer>(); 
    private List<Integer> list2 = new ArrayList<Integer>(); 

    public void stageOne() { 

     synchronized (lock1) { 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      list1.add(random.nextInt(100)); 
     } 

    } 

    public void stageTwo() { 

     synchronized (lock2) { 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      list2.add(random.nextInt(100)); 
     } 

    } 

    public void process() { 
     for(int i=0; i<1000; i++) { 
      stageOne(); 
      stageTwo(); 
     } 
    } 

    public void main() { 
     System.out.println("Starting ..."); 

     long start = System.currentTimeMillis(); 

     Thread t1 = new Thread(new Runnable() { 
      public void run() { 
       process(); 
      } 
     }); 

     Thread t2 = new Thread(new Runnable() { 
      public void run() { 
       process(); 
      } 
     }); 

     t1.start(); 
     t2.start(); 

     try { 
      t1.join(); 
      t2.join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     long end = System.currentTimeMillis(); 

     System.out.println("Time taken: " + (end - start)); 
     System.out.println("List1: " + list1.size() + "; List2: " + list2.size()); 
    } 
} 
+2

Нет причин. Вы действительно должны только синхронизировать «конечные» переменные. Если вы можете пометить свой 'List' как' final', вы можете просто синхронизировать его. Использование отдельного объекта отделяет проблемы и может быть принято, чтобы сделать код более понятным. –

+2

Согласен с Борисом. Один момент я бы добавил, что вы никогда не хотите блокировать поле, которое возвращается получателем. Поэтому, изолируя замок от любого поля, используемого для другой цели, вы устраняете эту возможность. –

+0

Спасибо @BoristheSpider и @John B. Зачем блокировать только 'final' переменные? Почему бы не использовать геттеры? –

ответ

4

Я не думаю, что мотивация для этого выражается в коде, вы дали, но является вообще передовой практики. Тем не менее, одна и та же самая лучшая практика требует, чтобы объекты блокировки были также final.

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

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

+0

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

+2

В любом случае нет никакой связи между объектом и его монитором - это просто еще один монитор. Единственная точка контакта между ними - несколько неудобный «удобный» синтаксис, который позволяет пометить метод как «синхронизированный». Эта функция на самом деле вызывала гораздо больше путаницы, чем удобство. –

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