談到線程同步,一般指如何對線程間共享數據的同步讀寫,如何避免混亂的讀寫結果。一個基本的解決辦法就是使用鎖(LOCK)。
iOS提供多種同步鎖的類和方法,這里介紹下基本用法。
1. NSLock:最基本的同步鎖,使用lock來獲得鎖,unlock釋放鎖。如果其它線程已經使用lock,這時lock方法會阻塞當前線程,直到其它線程調用unlock釋放鎖為止。NSLock鎖一般用於簡單的同步算法。比如生產者線程產生數據(produce),消費線程顯示數據(consume),可以這樣實現:
- (void)produce
{
while (1)
{
[theLock lock];
// create data
[theLock unlock];
}
}
- (void)consume
{
while (1)
{
if ([theLock tryLock])
{
// display data
[theLock unlock];
}
sleep(1.0); //sleep a while
}
}
NSLock的tryLock方法可以避免阻塞當前線程,如果不能獲得鎖則返回NO。也可使用:
- (BOOL)lockBeforeDate:(NSDate *)limit;
設置超時返回時間。
2. NSConditionLock,即條件鎖,可以設置自定義的條件來獲得鎖。比如上面的例子可以這樣改用條件鎖實現:
- (void)produce
{
while (1)
{
[theLock lockWhenCondition:NO_DATA];
// create data
[theLock unlockWithCondition:HAS_DATA];
}
}
- (void)consume
{
while (1)
{
if ([theLock tryLockWhenCondition:HAS_DATA])
{
// display data
[theLock unlockWithCondition:NO_DATA];
}
sleep(1.0); //sleep a while
}
}
3. NSCondition:條件(一種信號量),類似Java中的Condition,但有所不同的是NSCondition是鎖和條件的組合實現。wait方法用於線程的等待(相當於Java Condition的await()),然后通過signal方法通知等待線程(相當於Java Condition的signal()),或者broadcast通知所有等待的線程相當於Java Condition的signalAll())。一個簡單生產消費同步例子:
- (void)produce
{
[theLock lock];
// create data
hasData = YES;
[theLock signal]; //這時通知調用wait的線程結束等待並返回
[theLock unlock];
}
- (void)consume
{
[theLock lock];
while (!hasData)
[theLock wait]; //注意:這時其它線程的lock調用會成功返回
//display data
hasData = NO;
[theLock unlock];
}
4. NSRecursiveLock:遞歸鎖,顧名思義一般用於遞歸程序。它可以讓同一線程多次獲得鎖,解鎖次數也必須相同,然后鎖才能被其它線程獲得。看下官網文檔中的簡單例子就能明白:
void MyRecursiveFunction(int value)
{
[theLock lock];
if (value != 0)
{
--value;
MyRecursiveFunction(value);
}
[theLock unlock];
}
當然不只用於遞歸程序,類似Java中的ReentrantLock。
5. @synchronized實現對象鎖,類似Java中synchronized關鍵詞。一般這樣使用,但不多啰嗦了:
@synchronized(anObj)
{
//......
}