NSThread 是 Foundation 对线程的封装，具体实现一个线程可以继承 NSThread 实现 main 方法，如下示例中 main 方法会读写共享变量 self.shareData.count：
共享变量 MyShareData 的实现：
如下代码线程 A 和线程 B 各自累加共享变量 1000 次：
输出结果应该是 2000，结果却如下不是 2000，是因为产生了 Race Condition：
将属性修饰符从 nonatomic 改为 atomic：
运行一下，发现没有解决 Race Condition 的问题：
Properties are atomic by default so that synthesized accessors provide robust access to properties in a multithreaded environment—that is, the value returned from the getter or set via the setter is always fully retrieved or set regardless of what other threads are executing concurrently.
The @synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code. The @synchronized directive does what any other mutex lock would do—it prevents different threads from acquiring the same lock at the same time.
An NSLock object implements a basic mutex for Cocoa applications. The interface for all locks (including NSLock) is actually defined by the NSLocking protocol, which defines the lock and unlock methods. You use these methods to acquire and release the lock just as you would any mutex.
The NSRecursiveLock class defines a lock that can be acquired multiple times by the same thread without causing the thread to deadlock. A recursive lock keeps track of how many times it was successfully acquired. Each successful acquisition of the lock must be balanced by a corresponding call to unlock the lock. Only when all of the lock and unlock calls are balanced is the lock actually released so that other threads can acquire it.
An NSConditionLock object defines a mutex lock that can be locked and unlocked with specific values. You should not confuse this type of lock with a condition (see Conditions). The behavior is somewhat similar to conditions, but is implemented very differently.
Typically, you use an NSConditionLock object when threads need to perform tasks in a specific order, such as when one thread produces data that another consumes. While the producer is executing, the consumer acquires the lock using a condition that is specific to your program. (The condition itself is just an integer value that you define.) When the producer finishes, it unlocks the lock and sets the lock condition to the appropriate integer value to wake the consumer thread, which then proceeds to process the data.
The locking and unlocking methods that NSConditionLock objects respond to can be used in any combination. For example, you can pair a lock message with unlockWithCondition:, or a lockWhenCondition: message with unlock. Of course, this latter combination unlocks the lock but might not release any threads waiting on a specific condition value.
The NSCondition class provides the same semantics as POSIX conditions, but wraps both the required lock and condition data structures in a single object. The result is an object that you can lock like a mutex and then wait on like a condition.