我正在做这个多线程应用程序只是为了看看@synchronized指令是如何工作的。我读过如果所有线程都与@synchronized的参数具有相同的对象,那么它们都等待同一个锁。所以我想使用self作为参数,因为它对所有线程都是一样的 在这个应用程序中,有一个文本字段被所有线程多次编辑。我不关心性能,它只是一个测试所以我没有把@synchronized指令放在for之前,但在里面。
我使用的属性:
@property (weak) IBOutlet NSTextField *textField;
@property (nonatomic, copy) NSNumber* value;
@property (nonatomic,copy) NSMutableArray* threads;
代码:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
value= @0;
textField.objectValue= value;
for(int i=0; i<10; i++)
{
NSThread* thread=[[NSThread alloc]initWithTarget: self selector: @selector(routine:) object: nil];
[threads addObject: thread];
[thread start];
}
}
- (void) routine : (id) argument
{
for(NSUInteger i=0; i<100; i++)
{
@synchronized(self)
{
value= @(value.intValue+1);
textField.objectValue= value;
}
}
}
有时候应用程序会成功,我会看到1000作为文本字段值。但有时候不是,我担心这是饥饿,我在文本字段中看不到任何内容,它是空的。我尝试了调试但是很难看看有什么不对,因为失败的标准对我来说似乎很随意,有时它只是运作正常。
解
@synthesize threads,value, textField;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
value= @0;
threads=[[NSMutableArray alloc]initWithCapacity: 100];
for(NSUInteger i=0; i<100; i++)
{
NSThread* thread=[[NSThread alloc]initWithTarget: self selector: @selector(routine:) object: nil ];
[threads addObject: thread];
[thread start];
}
}
- (void) routine : (id) arg
{
for(NSUInteger i=0; i<1000; i++)
{
@synchronized(self)
{
value= @(value.intValue+1);
[textField performSelectorOnMainThread: @selector(setObjectValue:) withObject: value waitUntilDone: NO];
}
}
}
答案 0 :(得分:3)
您正在从非主线程访问NSTextField
,它是NSView
的子类。 That is not a safe thing to do。结果未定义;有时它似乎有效,有时却没有。
答案 1 :(得分:1)
您始终在后台线程中更新UI。这个不好。你应该这样做;
(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
value= @0;
textField.objectValue= value;
for(int i=0; i<10; i++)
{
NSThread* thread=[[NSThread alloc] initWithTarget: self selector: @selector(routine:) object: nil];
[threads addObject: thread];
[thread start];
}
}
- (void) routine : (id) argument
{
for(NSUInteger i=0; i<100; i++)
{
@synchronized(self)
{
value= @(value.intValue+1);
[textField performSelectorOnMainThread:@selector(setObjectValue:) withObject:value waitUntilDone: NO];
}
}
}
尝试锁定实例并使用sleep方法使其更加平滑。
要在后台线程中锁定变量,首先将其锁定,然后设置其值并将其解锁为;
[NSLock lock];
value=@(value.intValue+1)
[NSLock unlock];
但是,您已经拥有@synchronized,这使得它可以同时保护从多个线程访问的变量。我认为@synchonized块更容易理解。
在这种情况下,睡眠更合适。如果你在线程中放置了2秒的睡眠,那么你可以看到textField每2秒更改一次,它更加明显并且更有意义。
[NSThread sleepForTimeInterval:2000]
//在更新textField并查看效果后,将其置于循环内。
最好创建一个runloop并在某个runloop中执行该线程,这是一种更好的做法。