详解iOS多线程之2.NSThread的加锁@synchronized
那什么时候需要加锁呢,就是当多条线程同时操作一个变量时,就需要加锁了。
上代码
声明变量
@interfaceViewController() @property(strong,nonatomic)NSThread*thread1; @property(strong,nonatomic)NSThread*thread2; @property(strong,nonatomic)NSThread*thread3; @property(assign,nonatomic)intleftTickets; @end
实现代码
-(void)viewDidLoad{ [superviewDidLoad]; self.thread1=[[NSThreadalloc]initWithTarget:selfselector:@selector(sellTickets)object:nil]; self.thread2=[[NSThreadalloc]initWithTarget:selfselector:@selector(sellTickets)object:nil]; self.thread3=[[NSThreadalloc]initWithTarget:selfselector:@selector(sellTickets)object:nil]; self.thread1.name=@"thread1"; self.thread2.name=@"thread2"; self.thread3.name=@"thread3"; //总票数 self.leftTickets=10; } //点击屏幕开启线程 -(void)touchesBegan:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event{ [self.thread1start]; [self.thread2start]; [self.thread3start]; } -(void)sellTickets{ while(1){ @synchronized(self){ if(self.leftTickets>0){ [NSThreadsleepForTimeInterval:0.2]; intcount=self.leftTickets; self.leftTickets=count-1; NSLog(@"剩余的票数%d",self.leftTickets); NSLog(@"当前线程=%@",[NSThreadcurrentThread]); }else{ NSLog(@"票卖完了"); NSLog(@"退出线程%@",[NSThreadcurrentThread]); [NSThreadexit]; } } } }
打印日志
2016-11-0411:52:25.117TTTTTTTTTT[6753:74162]剩余的票数9
2016-11-0411:52:25.117TTTTTTTTTT[6753:74162]当前线程=<NSThread:x608000073880>{number=3,name=thread1}
2016-11-0411:52:25.393TTTTTTTTTT[6753:74163]剩余的票数8
2016-11-0411:52:25.393TTTTTTTTTT[6753:74163]当前线程=<NSThread:x608000074540>{number=4,name=thread2}
2016-11-0411:52:25.661TTTTTTTTTT[6753:74164]剩余的票数7
2016-11-0411:52:25.661TTTTTTTTTT[6753:74164]当前线程=<NSThread:x608000074580>{number=5,name=thread3}
2016-11-0411:52:25.932TTTTTTTTTT[6753:74162]剩余的票数6
2016-11-0411:52:25.933TTTTTTTTTT[6753:74162]当前线程=<NSThread:x608000073880>{number=3,name=thread1}
2016-11-0411:52:26.164TTTTTTTTTT[6753:74163]剩余的票数5
2016-11-0411:52:26.165TTTTTTTTTT[6753:74163]当前线程=<NSThread:x608000074540>{number=4,name=thread2}
2016-11-0411:52:26.438TTTTTTTTTT[6753:74164]剩余的票数4
2016-11-0411:52:26.439TTTTTTTTTT[6753:74164]当前线程=<NSThread:x608000074580>{number=5,name=thread3}
2016-11-0411:52:26.704TTTTTTTTTT[6753:74162]剩余的票数3
2016-11-0411:52:26.705TTTTTTTTTT[6753:74162]当前线程=<NSThread:x608000073880>{number=3,name=thread1}
2016-11-0411:52:26.975TTTTTTTTTT[6753:74163]剩余的票数2
2016-11-0411:52:26.976TTTTTTTTTT[6753:74163]当前线程=<NSThread:x608000074540>{number=4,name=thread2}
2016-11-0411:52:27.232TTTTTTTTTT[6753:74164]剩余的票数1
2016-11-0411:52:27.233TTTTTTTTTT[6753:74164]当前线程=<NSThread:x608000074580>{number=5,name=thread3}
2016-11-0411:52:27.505TTTTTTTTTT[6753:74162]剩余的票数0
2016-11-0411:52:27.505TTTTTTTTTT[6753:74162]当前线程=<NSThread:x608000073880>{number=3,name=thread1}
2016-11-0411:52:27.505TTTTTTTTTT[6753:74163]票卖完了
2016-11-0411:52:27.506TTTTTTTTTT[6753:74163]退出线程<NSThread:x608000074540>{number=4,name=thread2}
我们一般用@synchronized来给线程加锁。它有什么用呢:
(1)堵塞所在线程,线程里面剩下的任务只有当@synchronized里面的代码执行完毕才能继续往下执行,和队列的同步差不多是一个意思。
(2)当执行@synchronized里面的代码之前,所在线程要先检查是否有其他的线程执行里面的代码。如果没有,才继续往下执行。
再看打印日志里面最后一条,说明了只有线程“thread3”退出了,其他的线程没有退出。
我上篇文章讲,不用管线程的退出,任务执行完线程会自动退出。但是这是一个while循环啊!如果不退出线程,线程会一直执行。
-(void)sellTickets{ while(1){ @synchronized(self){ if(self.leftTickets>0){ [NSThreadsleepForTimeInterval:0.2]; intcount=self.leftTickets; self.leftTickets=count-1; NSLog(@"剩余的票数%d",self.leftTickets); NSLog(@"当前线程=%@",[NSThreadcurrentThread]); }else{ NSLog(@"票卖完了"); NSLog(@"退出线程%@",[NSThreadcurrentThread]); //不让线程退出 //[NSThreadexit]; } } } }
打印的日志
2016-11-0412:01:53.309TTTTTTTTTT[7110:78974]当前线程=<NSThread:x600000076f40>{number=4,name=thread2}
2016-11-0412:01:53.556TTTTTTTTTT[7110:78973]剩余的票数0
2016-11-0412:01:53.556TTTTTTTTTT[7110:78973]当前线程=<NSThread:x600000076fc0>{number=3,name=thread1}
2016-11-0412:01:53.556TTTTTTTTTT[7110:78975]票卖完了
2016-11-0412:01:53.557TTTTTTTTTT[7110:78975]退出线程<NSThread:x600000077240>{number=5,name=thread3}
2016-11-0412:01:53.558TTTTTTTTTT[7110:78974]票卖完了
2016-11-0412:01:53.559TTTTTTTTTT[7110:78974]退出线程<NSThread:x600000076f40>{number=4,name=thread2}
2016-11-0412:01:53.560TTTTTTTTTT[7110:78973]票卖完了
那又为什么只有线程thread2退出呢?(注:每次退出的线程是不确定的)因为当线程thread2退出了,并没有执行完@synchronized里的方法,线程thread1和线程thread3还在等thread2执行完了,它们好去执行呢。但是线程thread2已经死了,不可能再执行了。这就造成线程thread1和线程thread3一直都在内存里,没有被退出,造成了CPU不必要的开销,所以我们最好不要在@synchronized里面退出线程。
-(void)sellTickets{ while(1){ @synchronized(self){ if(self.leftTickets>0){ [NSThreadsleepForTimeInterval:0.2]; intcount=self.leftTickets; self.leftTickets=count-1; NSLog(@"剩余的票数%d",self.leftTickets); NSLog(@"当前线程=%@",[NSThreadcurrentThread]); } } if(self.leftTickets==0){ NSLog(@"票卖完了"); NSLog(@"退出线程%@",[NSThreadcurrentThread]); [NSThreadexit]; } } }
2016-11-0412:06:51.795TTTTTTTTTT[7295:81206]票卖完了
2016-11-0412:06:51.795TTTTTTTTTT[7295:81207]票卖完了
2016-11-0412:06:51.795TTTTTTTTTT[7295:81208]票卖完了
2016-11-0412:06:51.796TTTTTTTTTT[7295:81206]退出线程<NSThread:x60000026a3c0>{number=3,name=thread1}
2016-11-0412:06:51.796TTTTTTTTTT[7295:81207]退出线程<NSThread:x60000026a380>{number=4,name=thread2}
2016-11-0412:06:51.796TTTTTTTTTT[7295:81208]退出线程<NSThread:x60000026a740>{number=5,name=thread3}
这就是NSThread加锁以及加锁的一些注意事项。如果感觉对你有用,记得关注啊,也希望大家多多支持毛票票。