iOS多线程编程之NSThread的使用(转载)

本文介绍了iOS中使用NSThread进行多线程编程的方法,包括NSThread的创建与使用、线程间通信及线程同步等内容。通过具体示例展示了如何在实际应用中运用这些技术。

1、简介:

1.1 iOS有三种多线程编程的技术,分别是:

1、NSThread 

2、Cocoa NSOperation (iOS多线程编程之NSOperation和NSOperationQueue的使用

3、GCD  全称:Grand Central Dispatch( iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用

这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。

1.2 三种方式的优缺点介绍:

NSThread:

优点:NSThread 比其他两个轻量级

缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销

NSThread实现的技术有下面三种:

Cocoa operation 

优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。

Cocoa operation 相关的类是 NSOperation ,NSOperationQueue。NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。

GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。现在的iOS系统都升级到6了,所以不用担心该技术不能使用。

介绍完这三种多线程编程方式,我们这篇先介绍NSThread的使用。

2、NSThread的使用

2.1 NSThread 有两种直接创建方式:

- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument

第一个是实例方法,第二个是类方法

1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil]; 

 

2、NSThread* myThread = [[NSThread alloc] initWithTarget:self  
                                             selector:@selector(doSomething:)  
                                               object:nil];  
[myThread start]; 

2.2参数的意义: 

selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。

target  :selector消息发送的对象

argument:传输给target的唯一参数,也可以是nil

第一种方式会直接创建线程并且开始运行线程。
第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息。

2.3 PS:不显式创建线程的方法:

用NSObject的类方法  performSelectorInBackground:withObject: 创建一个线程:

[Obj performSelectorInBackground:@selector(doSomething) withObject:nil]; 

2.4 下载图片的例子:

2.4.1  新建singeView app

新建项目,并在xib文件上放置一个imageView控件。
按住control键拖到viewController.h文件中创建imageView IBOutlet 

ViewController.m中实现:
//  
//  ViewController.m  
//  NSThreadDemo  
//  
//  Created by rongfzh on 12-9-23.  
//  Copyright (c) 2012年 rongfzh. All rights reserved.  
//  
#import "ViewController.h"  
#define kURL @"http://avatar.youkuaiyun.com/2/C/D/1_totogo2010.jpg"  
@interface ViewController ()  
@end  
@implementation ViewController  
-(void)downloadImage:(NSString *) url{  
    NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];  
    UIImage *image = [[UIImage alloc]initWithData:data];  
    if(image == nil){  
          
    }else{  
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];  
    }  
}  
-(void)updateUI:(UIImage*) image{  
    self.imageView.image = image;  
}    
- (void)viewDidLoad  {  
    [super viewDidLoad];  
//    [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];  
       NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];  
      [thread start];  
}   
- (void)didReceiveMemoryWarning  {  
    [super didReceiveMemoryWarning];  
    // Dispose of any resources that can be recreated.  
}  
@end   
 
2.4.2线程间通讯

线程下载完图片后怎么通知主线程更新界面呢? 

[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:

用:performSelector:onThread:withObject:waitUntilDone: 

运行下载图片:

图片下载下来了。

2.3 线程同步

我们演示一个经典的卖票的例子来讲NSThread的线程同步:

.h

#import <UIKit/UIKit.h>  
@class ViewController;  
@interface AppDelegate : UIResponder <UIApplicationDelegate>  
{  
    int tickets;  
    int count;  
    NSThread* ticketsThreadone;  
    NSThread* ticketsThreadtwo;  
    NSCondition* ticketsCondition;  
    NSLock *theLock;  
}  
@property (strong, nonatomic) UIWindow *window;  
@property (strong, nonatomic) ViewController *viewController;  
@end  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
{  
    tickets = 100;  
    count = 0;  
    theLock = [[NSLock alloc] init];  
    // 锁对象  
    ticketsCondition = [[NSCondition alloc] init];  
    ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
    [ticketsThreadone setName:@"Thread-1"];  
    [ticketsThreadone start];  
    
    ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
    [ticketsThreadtwo setName:@"Thread-2"];  
    [ticketsThreadtwo start];  
      
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
    // Override point for customization after application launch.  
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
    self.window.rootViewController = self.viewController;  
    [self.window makeKeyAndVisible];  
    return YES;  
}  
  
- (void)run{  
    while (TRUE) {  
        // 上锁  
//     [ticketsCondition lock];  
        [theLock lock];  
        if(tickets >= 0){  
            [NSThread sleepForTimeInterval:0.09];  
            count = 100 - tickets;  
            NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  
            tickets--;  
        }else{  
            break;  
        }  
        [theLock unlock];  
//     [ticketsCondition unlock];  
    }  
}   
 

如果没有线程同步的lock,卖票数可能是-1.加上lock之后线程同步保证了数据的正确性。
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了。 

线程的顺序执行

他们都可以通过   [ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

#import "AppDelegate.h"  
#import "ViewController.h"  
@implementation AppDelegate    
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
{    
    tickets = 100;  
    count = 0;  
    theLock = [[NSLock alloc] init];  
    // 锁对象  
    ticketsCondition = [[NSCondition alloc] init];  
    ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
    [ticketsThreadone setName:@"Thread-1"];  
    [ticketsThreadone start];  
      
    ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
    [ticketsThreadtwo setName:@"Thread-2"];  
    [ticketsThreadtwo start];  
      
    NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];  
    [ticketsThreadthree setName:@"Thread-3"];  
    [ticketsThreadthree start];      
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
    // Override point for customization after application launch.  
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  
    self.window.rootViewController = self.viewController;  
    [self.window makeKeyAndVisible];  
    return YES;  
}  
  
-(void)run3{  
    while (YES) {  
        [ticketsCondition lock];  
        [NSThread sleepForTimeInterval:3];  
        [ticketsCondition signal];  
        [ticketsCondition unlock];  
    }  
}  
- (void)run{  
    while (TRUE) {  
        // 上锁  
        [ticketsCondition lock];  
        [ticketsCondition wait];  
        [theLock lock];  
        if(tickets >= 0){  
            [NSThread sleepForTimeInterval:0.09];  
            count = 100 - tickets;  
            NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  
            tickets--;  
        }else{  
            break;  
        }  
        [theLock unlock];  
        [ticketsCondition unlock];  
    }  
}  
 

wait是等待,我加了一个 线程3 去唤醒其他两个线程锁中的wait

其他同步

我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。

- (void)doSomeThing:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}

还有其他的一些锁对象,比如:循环锁NSRecursiveLock,条件锁NSConditionLock,分布式锁NSDistributedLock等等,可以自己看官方文档学习
转载:http://blog.youkuaiyun.com/totogo2010/article/details/8010231

转载于:https://www.cnblogs.com/lxlx1798/p/6642924.html

内容概要:本文详细介绍了“秒杀商城”微服务架构的设计与实战全过程,涵盖系统从需求分析、服务拆分、技术选型到核心功能开发、分布式事务处理、容器化部署及监控链路追踪的完整流程。重点解决了高并发场景下的超卖问题,采用Redis预减库存、消息队列削峰、数据库乐观锁等手段保障数据一致性,并通过Nacos实现服务注册发现与配置管理,利用Seata处理跨服务分布式事务,结合RabbitMQ实现异步下单,提升系统吞吐能力。同时,项目支持Docker Compose快速部署和Kubernetes生产级编排,集成Sleuth+Zipkin链路追踪与Prometheus+Grafana监控体系,构建可观测性强的微服务系统。; 适合人群:具备Java基础和Spring Boot开发经验,熟悉微服务基本概念的中高级研发人员,尤其是希望深入理解高并发系统设计、分布式事务、服务治理等核心技术的开发者;适合工作2-5年、有志于转型微服务或提升架构能力的工程师; 使用场景及目标:①学习如何基于Spring Cloud Alibaba构建完整的微服务项目;②掌握秒杀场景下高并发、超卖控制、异步化、削峰填谷等关键技术方案;③实践分布式事务(Seata)、服务熔断降级、链路追踪、统一配置中心等企业级中间件的应用;④完成从本地开发到容器化部署的全流程落地; 阅读建议:建议按照文档提供的七个阶段循序渐进地动手实践,重点关注秒杀流程设计、服务间通信机制、分布式事务实现和系统性能优化部分,结合代码调试与监控工具深入理解各组件协作原理,真正掌握高并发微服务系统的构建能力。
数字图像隐写术是一种将秘密信息嵌入到数字图像中的技术,它通过利用人类视觉系统的局限性,在保持图像视觉质量的同时隐藏信息。这项技术广泛应用于信息安全、数字水印和隐蔽通信等领域。 典型隐写技术主要分为以下几类: 空间域隐写:直接在图像的像素值中进行修改,例如LSB(最低有效位)替换方法。这种技术简单易行,但对图像处理操作敏感,容易被检测到。 变换域隐写:先将图像转换到频域(如DCT或DWT域),然后在变换系数中嵌入信息。这类方法通常具有更好的鲁棒性,能抵抗一定程度的图像处理操作。 自适应隐写:根据图像的局部特性动态调整嵌入策略,使得隐写痕迹更加分散和自然,提高了安全性。 隐写分析技术则致力于检测图像中是否存在隐藏信息,主要包括以下方法: 统计分析方法:检测图像统计特性的异常,如直方图分析、卡方检测等。 机器学习方法:利用分类器(如SVM、CNN)学习隐写图像的区分特征。 深度学习方法:通过深度神经网络自动提取隐写相关特征,实现端到端的检测。 信息提取过程需要密钥或特定算法,通常包括定位嵌入位置、提取比特流和重组信息等步骤。有效的隐写系统需要在容量、不可见性和鲁棒性之间取得平衡。 随着深度学习的发展,隐写与反隐写的技术对抗正在不断升级,推动了这一领域的持续创新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值