您的位置:首页 > 移动开发 > IOS开发

如何退出当前线程及线程安全

2016-05-14 19:35 323 查看
退出当前线程的代码

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent
*)event{

   //
创建线程
   
NSThread *thread =[[NSThread
alloc]initWithTarget:self
selector:@selector(threadDemo2)
object:nil];

    //开启线程
    [thread
start];
}

-(void)threadDemo2{

    NSLog(@"%@",[NSThread
currentThread]);
   
for (int i =
0; i < 20; ++i) {
       
NSLog(@"i:%d",i);
       
if (i == 10) {
           
/*

             This method uses the currentThread class method to access the current thread. Before exiting the thread, this method posts the NSThreadWillExitNotification with the thread being exited to the default notification center. Because notifications are
delivered synchronously, all observers of NSThreadWillExitNotification are guaranteed to receive the notification before the thread exits.

             这个方法使用 currentThread访问当前线程。在推出当前线程之前,这个方法发出一个NSThreadWillExitNotification通知給到通知中心。因为通知呗同步地发送,所有的NSThreadWillExitNotification的观察者被确保收到这个通知,在退出当前线程之前。

             Invoking this method should be avoided as it does not give your thread a chance to clean up any resources it allocated during its execution.

             唤醒这个方法应该避免,因为他不会給你的线程一个清除运行过程中分配的资源的机会。

             */

            
            [NSThread
exit];// 退出当前的线程
           
NSLog(@"come here");
        }
    }
}

/*

     The stack size of the receiver, in bytes.

     //栈区的大小
以字节为单位

     This value must be in bytes and a multiple of 4KB.

     这个值必须是以字节为单位,可以是4kb的倍数

     To change the stack size, you must set this property before starting your thread. Setting the stack size after the thread has started changes the attribute size (which is reflected by the stackSize method), but it does not affect the actual number of pages
set aside for the thread.

     为了改变展区的大小,你必须设置它的优先级在开启线程之前。设置栈区的大小在线程已经启动之后,改变这个属性(它被设置调用stackSize方法),但是他不禅城实际的分配空间的效果。

     */
-------------------------------
多条线程同时访问一块资源

- (void)viewDidLoad {

    [super
viewDidLoad];

   

    self.threadA =[[NSThread
alloc]initWithTarget:self
selector:@selector(saleTicket)
object:nil];
   
self.threadA.name =
@"线程A";

    self.threadB =[[NSThread
alloc]initWithTarget:self
selector:@selector(saleTicket)
object:nil];
   
self.threadB.name =
@"
11ab8
线程B";

    self.threadC =[[NSThread
alloc]initWithTarget:self
selector:@selector(saleTicket)
object:nil];
   
self.threadC.name =
@"线程C";
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent
*)event{
    [self.threadA
start];
    [self.threadB
start];
    [self.threadC
start];
}
-(void)saleTicket{

    self.leftTicketCount =
100;
   
while (YES) {
       
if (self.leftTicketCount >
0) {
           
self.leftTicketCount --;
           
NSLog(@"%@卖票,当前还剩下%ld张票",[NSThread
currentThread].name,self.leftTicketCount);
        }else{
           
NSLog(@"已卖完");
           
return;
        }
    }
}
--执行结果

 线程C卖票,当前还剩下99张票
2016-05-14 21:00:31.377 03-
线程安全[2725:348472]
线程B卖票,当前还剩下99张票
2016-05-14 21:00:31.377 03-
线程安全[2725:348471]
线程A卖票,当前还剩下99张票
2016-05-14 21:00:31.377 03-
线程安全[2725:348473]
线程C卖票,当前还剩下98张票

 线程B卖票,当前还剩下82张票
2016-05-14 21:00:31.380 03-
线程安全[2725:348471]
线程A卖票,当前还剩下81张票
2016-05-14 21:00:31.427 03-
线程安全[2725:348472]
线程B卖票,当前还剩下79张票
2016-05-14 21:00:31.427 03-
线程安全[2725:348473]
线程C卖票,当前还剩下80张票
2016-05-14 21:00:31.427 03-
线程安全[2725:348471]
线程A卖票,当前还剩下78张票
可以看到同时访问同一块资源的时候就会出现数据安全问题
-->如果在卖票之前线程睡眠一段时间,数据混乱更加明显

--->加同步锁 ,当前线程访问的时候加锁,读取数据,写入数据后,再打开同步锁,其他对象可以就访问这个资源。

--->我先把同步锁加载外面---加载外面的结果是只能保证一个线程能够卖完

-(void)saleTicket{

    self.leftTicketCount =
100;

    

    @synchronized(self) {

        
       
while (YES) {
           
if (self.leftTicketCount >
0) {

                

                //[NSThread sleepForTimeInterval:1.0];
               
self.leftTicketCount --;
               
NSLog(@"%@卖票,当前还剩下%ld张票",[NSThread
currentThread].name,self.leftTicketCount);
            }else{
               
NSLog(@"已卖完");
               
return;
            }
        }
    }
}
输出结果:

7891] 线程A卖票,当前还剩下7张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下6张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下5张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下4张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下3张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下2张票
2016-05-14 21:09:27.961 03-
线程安全[2780:357891]
线程A卖票,当前还剩下1张票
2016-05-14 21:09:27.962 03-
线程安全[2780:357891]
线程A卖票,当前还剩下0张票
锁在卖票的代码里面呢 ,也出错 会出现负数

-(void)saleTicket{

    self.leftTicketCount =
100;
       
while (YES) {
           
if (self.leftTicketCount >
0) {
               
@synchronized(self) {

                //[NSThread sleepForTimeInterval:1.0];
               
self.leftTicketCount --;
               
NSLog(@"%@卖票,当前还剩下%ld张票",[NSThread
currentThread].name,self.leftTicketCount);
                }
            }else{
               
return;
            }
        }

//    }
}
输出结果:

 线程A卖票,当前还剩下1张票
2016-05-14 21:11:46.893 03-
线程安全[2802:360854]
线程B卖票,当前还剩下0张票
2016-05-14 21:11:46.894 03-
线程安全[2802:360855]
线程C卖票,当前还剩下-1张票
2016-05-14 21:11:46.894 03-
线程安全[2802:360853]
线程A卖票,当前还剩下-2张票

 
这样加锁才是正确的做法

-(void)saleTicket{

    self.leftTicketCount =
100;
       
while (YES) {

            @synchronized(self) {
           
if (self.leftTicketCount >
0) {
               
self.leftTicketCount --;
               
NSLog(@"%@卖票,当前还剩下%ld张票",[NSThread
currentThread].name,self.leftTicketCount);
            }else{
               
return;
            }
        }
    }
}

其实这个加锁事利用了线程同步,线程同步,就是多条线程在同一条线程上按顺序执行。

互斥锁:上面这个案例就是加一个互斥锁

原子属性和非原子属性 atomic & nonatomic
@property修饰的属性,不加nonatomic默认就是atomic.
atomic:修饰的属性默认是线程安全的。会给属性的setter方法加锁
nonatomic:开发中建议使用这个,因为移动设备资源少,atomic需要消耗大量的 CPU资源。

关于iOS开发的建议
1.建议所有的属性都用nonatomic 
2.尽量避免多条线程同时访问同一块资源。
3.尽量将加锁,资源抢夺的业务逻辑交给服务器,减少移动端的压力
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios开发