Когда мы говорим о встроенной блокировке, мы ссылаемся на объект, для которого мы запрашиваем блокировку или для синхронизированного метода?
Блокировка находится на объекте или на его методе синхронизации?
Я в замешательстве!
Когда мы говорим о встроенной блокировке, мы ссылаемся на объект, для которого мы запрашиваем блокировку или для синхронизированного метода?
Блокировка находится на объекте или на его методе синхронизации?
Я в замешательстве!
Внутренние блокировки находятся на объекте:
class A
{
public synchronized void method1(){...}
public synchronized void method2(){...}
}
Если поток A находится в методе 1, то threadB не может ввести метод2.
В Java внутренняя блокировка подразумевается при каждом использовании синхронизированного ключевого слова
Каждое использование синхронизированного ключевого слова связано с одним из двух типов встроенной блокировки:
"блокировка экземпляра", прикрепленная к одному объекту
a "статический замок", прикрепленный к классу
Если метод объявлен как синхронизированный, он будет получать либо блокировку экземпляра, либо статическую блокировку при ее вызове в зависимости от того, является ли это методом экземпляра или статическим методом.
Два типа блокировки имеют сходное поведение, но полностью независимы друг от друга.
Приобретение блокировки экземпляра блокирует другие потоки только от вызова метода синхронизированного экземпляра; он не блокирует другие потоки от вызова несинхронизированного метода и не блокирует их от вызова статического синхронизированного метода.
Аналогично, получение статической блокировки блокирует другие потоки только от вызова статического синхронизированного метода; он не блокирует другие потоки от вызова несинхронизированного метода и не блокирует их от вызова метода синхронизированных экземпляров.
За пределами заголовка метода синхронизированный (this) получает блокировку экземпляра.
Статическая блокировка может быть получена за пределами заголовка метода двумя способами:
synchronized (Blah.class), используя литерал класса
synchronized (this.getClass()), если объект доступен
Синхронизированные методы блокируют метод объекта
synchronized void methodA () {
....
}
как-то эквивалентно
void methodA () {
synchronized (this) {
....
}
}
Замок является частью объекта. Каждый объект имеет один, и он может быть заблокирован двумя способами:
synchronized
для метода экземпляра класса для блокировки связанного объектаsynchronized(object) {}
Аналогично, вы можете заблокировать класс объекта вместо самого объекта (указывается отдельно, чтобы понять модификатор synchronized
с помощью метода static
):
synchronized
для статического метода класса для блокировки классаsynchronized(clazz) {}
, где clazz
- это класс объектаЗаблокирован объект. В Java каждый объект является monitor
private int count = 0;
public synchronized void countFunc(){
count++;
}
Thread t1 = new Thread(new Runnable(){
public void run(){
for(int i=0;i<1000;i++){
countFunc();
}}});
Thread t2 = new Thread(new Runnable(){
public void run(){
for(int i=0;i<1000;i++){
countFunc();
}}});
В приведенном выше примере у меня есть 2 потока, пытающихся увеличить значение count. И чтобы предотвратить чередование потоков, я пытаюсь захватить внутреннюю блокировку с помощью синхронизированного ключевого слова.
Окончательно, В этом примере блокировка содержит блок countFunc с ключевым словом синхронизированное и блокировка. > на переменной count. Надеюсь, что это поможет
Замок находится в объекте.
Посмотрите на страницу руководства java на встроенные блокировки
Каждый объект имеет связанный с ним встроенный замок. По соглашению поток, который нуждается в эксклюзивном и последовательном доступе к полям объекта, должен получить внутреннюю блокировку объекта перед доступом к ним, а затем освободить внутреннюю блокировку, когда она будет выполнена с ними. Говорят, что поток имеет собственный замок между временем, когда он приобрел замок, и освободил блокировку.
Пока поток имеет встроенную блокировку, ни один другой поток не может получить одну и ту же блокировку. Другой поток будет блокироваться, когда он попытается получить блокировку.
Два способа использования встроенных замков:
Синхронизированные методы:
Когда поток вызывает метод synchronized
, он автоматически получает встроенную блокировку для этого объекта метода и освобождает его при возврате метода.
например.
public synchronized void incrementCounter(){
++counter;
}
Синхронизированные операторы
В отличие от методов synchronized
, операторы synchronized
должны указывать объект, который обеспечивает внутреннюю блокировку
public int getCounter(){
synchronized(this){
return counter;
}
}
Полный пример:
public class SynchronizedDemo{
private int counter = 0;
public SynchronizedDemo(){
}
public synchronized void incrementCounter(){
++counter;
}
public int getCounter(){
synchronized(this){
return counter;
}
}
public static void main(String[] args){
SynchronizedDemo object = new SynchronizedDemo();
for ( int i=0; i < 5; i++){
Thread t = new Thread(new SimpleRunnable(object));
t.start();
}
}
}
class SimpleRunnable implements Runnable{
private SynchronizedDemo object;
public SimpleRunnable(SynchronizedDemo obj){
this.object = obj;
}
public void run(){
object.incrementCounter();
System.out.println("Counter:"+object.getCounter());
}
}
Примечание. Этот пример написан только для демонстрации различных способов использования встроенных блокировок. Использование AtomicInteger для переменной счетчика - правильный подход для этого типа прецедента.