2017-01-26 2 views
0

Я сейчас читаю о Intrinsic Locks and Synchronization на Oracle.com, откуда я пришел к этому конкретному примеру:Сущностных Замки и синхронизация

Синхронных заявления также полезны для улучшения параллелизма с мелкозернистой синхронизацией. Предположим, например, что класс MsLunch имеет два поля экземпляра: c1 и c2, которые никогда не используются вместе. Все обновления этих полей должны быть синхронизированы, но нет никаких причин помешать обновлению c1 с обновлением c2 - и это уменьшает параллелизм, создавая ненужную блокировку. Вместо использования синхронизированных методов или с использованием связанного с этим блокировки мы создаем два объекта исключительно для обеспечения блокировок.

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    private Object lock1 = new Object(); 
    private Object lock2 = new Object(); 

    public void inc1() { 
     synchronized(lock1) { 
      c1++; 
     } 
    } 

    public void inc2() { 
     synchronized(lock2) { 
      c2++; 
     } 
    } 
} 

До этого раздела, synchronized методы, где объясняется:

public synchronized void increment() { 
    this.c++; 
} 

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

public void increment() { 
    synchronized(this) { 
     c++; 
    } 
} 

если Я не добавляю функциональность в increment(), это правильно?

Мой вопрос теперь приходит из фразы:

, но нет никаких причин, чтобы предотвратить обновление c1 от того перемежаемого с обновлением c2

Я не уверен, если я полностью понять, что «чередуется» означает в этом контексте. Означает ли это, что если я, например? удалить lock2 из MsLunch Например:

public class MsLunch { 
    private long c1 = 0; 
    private long c2 = 0; 
    private Object lock1 = new Object(); 
    // private Object lock2 = new Object(); // 'lock2' is no more! 

    public void inc1() { 
     synchronized(lock1) { 
      c1++; 
     } 
    } 

    public void inc2() { 
     synchronized(lock1) { // Using 'lock1' here too 
      c2++; 
     } 
    } 
} 

я мог попасть в неприятности с блокировкой? Скажите thread-1 пробегает inc1(), получает блокировку от lock1, но подвешивается перед тем, как увеличить или отменить блокировку. Теперь thread-2 вводит inc2(), где создается еще одна блокировка для lock1. Это то, чего избегают, используя другой lock2, и является ли это причиной того, что я бы не использовал просто в качестве шлюза-провайдера? Или другими словами: Может ли это вызвать проблему?

+0

Нет, вы не можете попасть в * проблему *, вы просто не должны одновременно увеличивать «c1» и «c2», поскольку они имеют одну и ту же блокировку (независимо от того, является ли это «этим» или отдельный 'lock1') и поэтому имеют зависимость между ними через блокировку. – Kayaman

+0

@ Кайаман. О, немецкий перевод «чередующихся» - это нечто вроде «друг в друга» или «друг в друга», поэтому я немного смутился. Но почему это предотвращает «c1» и «c2» одновременно? В примере 'lock1'-only, если' lock1' содержит блокировку «* где угодно» в коде, означает ли это, что он будет блокироваться и в другом месте? Поэтому 'thread-2' должен ждать' thread-1', чтобы обновить 'c1', прежде чем он сможет обновить' c2'. Это также подразумевает, что каждый объект может одновременно обеспечивать * one * lock одновременно, что мне просто не ясно было прочитать главу. – displayname

+0

Да, каждый объект обеспечивает один замок за раз. Вот и вся идея, почему синхронизация работает так, как будто. – Kayaman

ответ

2

Два замка здесь только для того, чтобы иметь возможность увеличить c1 и c2 самостоятельно и не дожидаться, когда замок будет выпущен. Поэтому, если Thread-1 входит в блок синхронизации в c1 и получает lock1, другой Thread-2 может увеличить c2, не дожидаясь, когда thread-1 освободит замок.


Важно отметить:

Использование this как эмиссионный монитор имеет собственную проблему, так как ссылка на экземпляр MsLunch виден снаружи MsLunch. Например.Thread-3 можно приобрести замок для: synchronized (msLunchInstance) за пределами этого класса.

+0

Спасибо! +1 для объяснения относительно 'this'. Я не думал об этом значении - использование 'this' действительно могло бы скрыть некоторые проблемы с производительностью в * очень * грубом способе, если я получу это правильно! : D – displayname

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