2016-02-17 3 views
0

Я новичок в Java и пытаюсь изучить концепцию синхронных операторов. Я видел абзац и код ниже из Java Tutorial Oracle. Мой вопрос:Синхронизированные операторы - создавать объекты для обеспечения блокировок, поэтому обновление c1 не будет чередоваться с обновлением c2

1) В каких обстоятельствах обновление c1 чередуется с обновлением c2.

2) Как блокировать объект 'lock1' и 'lock2' предотвращать обновление c1 чередуется с обновлением c2.

Я действительно пытаюсь понять концепцию.

Синхронизированные операторы также полезны для улучшения параллелизма с мелкозернистой синхронизацией . Предположим, например, что класс 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++; 
     } 
    } 
} 
+1

1) Thread 1 вызывает inc1, в то время как Thread 2 вызывает inc2. 2) Вы читаете это неправильно. Использование 2 блокировок НЕ предотвращает чередование обновлений c1 с обновлениями c2. Это хорошо, потому что (как говорится в тексте) НЕТ НУЖНО. Синхронизация на 'this' вместо этого предотвратит одновременное выполнение inc1 и inc2. –

+1

Обратите внимание, что если вы не сможете сделать объекты блокировки окончательными, теоретически существует проблема для проблем. – chrylis

ответ

1

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

MsLunch ml = new MsLunch(); 

Thread thread1 = new Thread() { 
    public void run() { while (true) ml.inc1(); } 
}; 

Thread thread2 = new Thread() { 
    public void run() { while (true) ml.inc2(); } 
}; 

thread1.start(); 
thread2.start(); 

Есть теперь две нити, работающие параллельно, один, который вызывает inc1() в цикле и другой, который вызывает inc2() в цикле.

Имея отдельные замки для этих двух методов, два потока не будут мешать друг другу. Если у вас есть общий замок, то inc1() и inc2() не смогут работать одновременно. Каждый раз, когда вы вызываете один, другой будет блокироваться до завершения первого вызова.

Thread thread3 = new Thread() { 
    public void run() { while (true) ml.inc2(); } 
}; 

Контраст это к тому, что произойдет, если добавить третий поток, который также вызывает inc2(). Тема № 1 может звонить по номеру inc1() так же быстро, как нравится. Между тем, темы №2 и №3 оба хотят позвонить inc2(), чтобы они сражались друг с другом, чтобы сделать это. Если поток # 2 вызывает inc2(), тогда поток №3 будет блокироваться до завершения этого вызова. И наоборот, если поток №3 находится посреди вызова, то поток # 2 должен будет ждать.

+0

Большое вам спасибо! Я изо всех сил старался, но теперь понял! еще раз спасибо! – Thor

1

Когда у вас есть метод синхронизируется:

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

Он неявно преобразуется в:

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

SO, если вы сделаете как inc1 и inc2синхронизируется методы, то они оба должны получить текущий объект (this), а затем приращение.

Но так как и c2++ являются независимыми, они не должны блокироваться, потому что мы используем один замок. Мы должны гарантировать, что несколько вызовов на inc1() и inc2() должны быть заблокированы отдельными изолированными способами, то есть доступ к inc1() потоком 1 не должен блокировать доступ к inc2() потоком-2. При этом будут иметь разные блокировки.

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