If you’re just getting started with threading in Objective-C, it won’t be long before you’ll need to make some thread-safe modifications to objects. One of the many useful tools that Objective-C gives us is the @synchronizeddirective. From the documentation:
The
@synchronizeddirective is a convenient way to create mutex locks on the fly in Objective-C code. The@synchronizeddirective does what any other mutex lock would do—it prevents different threads from acquiring the same lock at the same time.
Using @synchronized is super easy
@synchronized(key) {
// thread-safe code goes here
}
Examples!
First we’re going to create an NSMutableArray and fill it with garbage.
bigArray = [NSMutableArray arrayWithCapacity:5];
for (int i = 0; i < 5; i++) {
[bigArray addObject:[NSString stringWithFormat:@"object-%i", i]];
}
And a method to display/modify the array.
- (void)updateBigArray:(NSString *)value {
for (int j = 0; j < bigArray.count; j++) {
NSString *currentObject = [bigArray objectAtIndex:j];
[bigArray replaceObjectAtIndex:j withObject:[currentObject stringByAppendingFormat:@"-%@", value]];
NSLog(@"%@", [bigArray objectAtIndex:j]);
}
}
Now let’s call our method on two separate threads. Notice I’m sending foo in for both of them. I’ll explain why in a bit.
NSString *foo = @"foo";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self updateBigArray:foo];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self updateBigArray:foo];
});
This gives us the output:
object-0-foo object-0-foo object-1-foo-foo object-1-foo object-2-foo object-2-foo object-3-foo object-3-foo object-4-foo-foo object-4-foo
Both threads are working over the top of each other which could lead to app crashes depending on what you’re doing. So let’s update our method to use@synchronized with value as our lock key.
- (void)updateBigArray:(NSString *)value {
@synchronized (value) {
for (int j = 0; j < bigArray.count; j++) {
NSString *currentObject = [bigArray objectAtIndex:j];
[bigArray replaceObjectAtIndex:j withObject:[currentObject stringByAppendingFormat:@"-%@", value]];
NSLog(@"%@", [bigArray objectAtIndex:j]);
}
}
}
object-0-foo object-1-foo object-2-foo object-3-foo object-4-foo object-0-foo-foo object-1-foo-foo object-2-foo-foo object-3-foo-foo object-4-foo-foo
That looks a lot better. What’s happening is that our @synchronized block effectively pauses one thread, allowing the other thread access to the block, then un-pauses it once the first has finished.
So what about the key?
This is where it gets interesting. If you pass the same object to@synchronized as the key, it will get paused (which we just saw). However, if you send a different object than the key it will get through. Remember when we passed foo through twice? Let’s pass something else the second time instead.
NSString *foo = @"foo";
NSString *bar = @"bar";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self updateBigArray:foo];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self updateBigArray:bar];
});
object-0-foo object-0-bar object-1-foo object-1-bar object-2-foo object-2-foo-bar object-3-foo object-3-foo-bar object-4-foo object-4-foo-bar
There could be reasons why you would want to lock on value, but in this case it would be smarter to use a different key.
Let’s use
@synchronized (bigArray) {
...
instead of
@synchronized (value) {
...
object-0-foo
object-1-foo
object-2-foo
object-3-foo
object-4-foo
object-0-foo-bar
object-1-foo-bar
object-2-foo-bar
object-3-foo-bar
object-4-foo-bar
In the end
@synchronized is a great shorthand mutex lock. It may not be the most efficient lock, but chances are you won’t notice. If you’re just getting started with threading, I highly recommend getting more familiar with it.
本文介绍了Objective-C中使用@synchronized指令来创建动态互斥锁,防止多线程同时访问同一对象,确保线程安全。通过实例展示了如何在不同线程间同步操作数组,并解释了使用相同或不同锁键的重要性。
1317

被折叠的 条评论
为什么被折叠?



