В 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 освободит память, используемую этим объектом, и выделит другую.
Объект, переданный в директиву
blockquote>@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++; } } }
@synchronized должен передавать один и тот же объект каждый раз. Так что @synchronized (self) будет работать лучше всего.
@synchronized([MyClass class])
или @ synchronized(someObj)
.
– Martin R
18 March 2014 в 14:07