@synchronized в объекте C [дубликат]

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

5
задан Basheer_CAD 18 March 2014 в 13:58
поделиться

2 ответа

Из документации :

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

Так что это зависит от то, что вы хотите защитить от выполнения одновременно, и есть приложения для всех трех случаев.

Например, в

-(void)addToMyArray1:(id)obj
{
    @synchronized(self) {
        [self.myArray1 addObject:obj];
    }
}

-(void)addToMyArray2:(id)obj
{
    @synchronized(self) {
        [self.myArray2 addObject:obj];
    }
}

оба блока @synchronized не могут быть выполнены одновременно два потока, вызывающие метод на одном и том же экземпляре (self), тем самым защищая одновременный доступ к массивам из разных потоков.

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

-(void)addToMyArray1:(id)obj
{
    @synchronized(self.myArray1) {
        [self.myArray1 addObject:obj];
    }
}

-(void)addToMyArray2:(id)obj
{
    @synchronized(self.myArray2) {
        [self.myArray2 addObject:obj];
    }
}

Теперь одновременный доступ к self.myArray1 и self.myArray2 из разных потоков по-прежнему защищен, но независимо друг от друга.

Блокировка класса может использоваться для защиты доступа к глобальной переменной. Это просто тривиальный пример демонстрационных целей:

static int numberOfInstances = 0;

-(id)init
{
    self = [super init];
    if (self) {
        @synchronized([self class]) {
            numberOfInstances++;
        }
    }
}
10
ответ дан Martin R 18 August 2018 в 06:55
поделиться
  • 1
    хороший ответ @MartinR, лучше, чем ваш старый;) – Basheer_CAD 18 March 2014 в 14:41
  • 2
    лучше пройти критический раздел, чем передавать себя каждый раз вправо? в этом случае _obj – Basheer_CAD 18 March 2014 в 14:42
  • 3
    @Basheer_CAD: Я не понимаю вас. Что такое _obj? – Martin R 18 March 2014 в 14:44
  • 4
    например, я использую метод для изменения _obj (запись несколькими потоками), лучше использовать @synchronized (_obj), а затем изменить этот объект внутри {...}. На всякий случай self используется как токен в другом блоке @synchr .. из другого потока? – Basheer_CAD 18 March 2014 в 14:47
  • 5
    @Basheer_CAD: Да, если у вас есть один объект для защиты (как массивы в моем ответе), вы можете просто заблокировать этот объект (это на самом деле проще, и я соответствующим образом обновил ответ). - Но могут быть более сложные случаи (например, последовательность заявлений для защиты), которым необходим выделенный замок. – Martin R 18 March 2014 в 14:52

@synchronized должен передавать один и тот же объект каждый раз. Так что @synchronized (self) будет работать лучше всего.

-1
ответ дан Aaron Bratcher 18 August 2018 в 06:55
поделиться
  • 1
    Это зависит от того, что вы хотите защитить. Существуют также варианты использования для @synchronized([MyClass class]) или @ synchronized(someObj). – Martin R 18 March 2014 в 14:07
  • 2
    @MartinR, да, возможно, когда у вас синглтон? – Basheer_CAD 18 March 2014 в 14:07
  • 3
    Если у вас синглтон, это не повлияет, потому что есть только один экземпляр. Нет, это просто зависит от ситуации. Если выполнение одного и того же кода для любого другого объекта того же класса будет проблемой, вы синхронизируете его с классом. Также следует помнить: «синхронизированный» следует использовать в течение как можно меньшего количества времени (так что все вычисления вне «синхронизированы») и избегают вложенных «синхронных» @ заявления на разных объектах, чтобы избежать взаимоблокировок. – gnasher729 18 March 2014 в 15:27
Другие вопросы по тегам:

Похожие вопросы: