多线程枷锁

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

1.、NSThread 

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

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

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

这篇我们主要介绍和使用NSThread,后面会继续2、3 的讲解和使用。
1.2 三种方式的有缺点介绍:

NSThread:

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

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

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

Technology

Description

Cocoa threads

Cocoa implements threads using the NSThread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads. For more information, see “Using NSThread” and “Using NSObject to Spawn a Thread.”

POSIX threads

POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see “Using POSIX Threads”

Multiprocessing Services

Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. This technology is available in OS X only and should be avoided for any new development. Instead, you should use the NSThread class or POSIX threads. If you need more information on this technology, see Multiprocessing Services Programming Guide.
一般使用cocoa thread 技术。

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

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

[cpp] view plaincopy

    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键拖到viewControll

er.h文件中创建imageView IBOutlet 

ViewController.m中实现:
[cpp] view plaincopy

    //
    //  ViewController.m
    //  NSThreadDemo
    //
    //  Created by rongfzh on 12-9-23.
    //  Copyright (c) 2012年 rongfzh. All rights reserved.
    //  

    #import "ViewController.h"
    #define kURL @"http://avatar.csdn.net/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

[cpp] view plaincopy

    #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  

[cpp] view plaincopy

    - (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]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。

比如:

[cpp] view plaincopy

    #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等等,可以自己看官方文档学习

NSThread下载图片的例子代码:http://download.csdn.net/detail/totogo2010/4591149

著作权声明:本文由http://blog.csdn.net/totogo2010/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
时间: 2024-08-24 06:36:16

多线程枷锁的相关文章

JAVA基础9(多线程)

1:多线程 (1)线程是依赖于进程而存在的. A.进程正在运行的应用程序 B.线程进程的执行路径,执行单元 (2)多线程的两种方案: 继承Thread类: 实现Runable接口: public class MyThread implements Runnable{ //实现runnable接口 public void run() { //启动该线程对象之后,需要执行的代码 for (int i = 0; i < 10; i++) { System.out.println(i); } } } p

Java中的多线程你只要看这一篇就够了

Java中的多线程你只要看这一篇就够了 引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其实只有一半对,因为反应"多角色"的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的"生产者,消费者模型". 很多人都对其中的一些概念不够明确,如同步.并发等等,让我

多线程 这一篇仔细看

引 如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”. 很多人都对其中的一些概念不够明确,如同步.并发等等,让我们先建立一个数据字典,以免产生误会. 多线程:指的是这个程序(一个进程

网络开始---多线程---线程的安全问题(了解)(四)

1 // 2 /** 3 * 线程的注意点 4 1.不要同时开太多线程,(1-3条即可,最多不要超过5条) 5 6 线程概念: 7 1.主线程: UI线程,显示.刷新UI界面.处理UI控件的事件 8 2.子线程(异步线程.后台线程) 9 10 3.不要把耗时的操作放在主线程,要放在子线程中执行 11 12 13 这里是3个窗口卖票的案例 14 */ 15 16 #import "HMViewController.h" 17 18 @interface HMViewController

[转]Java中的多线程你只要看这一篇就够了

如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”. 很多人都对其中的一些概念不够明确,如同步.并发等等,让我们先建立一个数据字典,以免产生误会. 多线程:指的是这个程序(一个进程)运

基于JAVA语言的多线程技术

1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资源的基本单位:线程是操作系统进行调度,时间分配的基本单位: 进程由内核对象和地址空间两部分构成,内核对象就是一小块记录进程信息的内存,只允许操作系统访问:地址空间就是存放数据和程序的空间: 2.多线程运行机制 对于单个CPU,在每个时间点只能只能执行一个线程,多线程的实现是基于对时间片的轮回机制的,

iOS开发——实用技术OC篇&amp;多线程整合

多线程整合 本文知识对iOS开发中多线程的一些知识整合,关于一些概念和技术问题并没有过多的介绍,如果你想了解更多请查看笔者之前写的iOS开发之多线程详解(比较完整):但是有部分涉及到之前文章中没有的技术点和常识,比如加锁的方式,面试相关的,还有一些关于GCD的高级用法,希望你能认真看完,或许可以收获到很多! http://www.cnblogs.com/iCocos/p/4553103.html http://www.cnblogs.com/iCocos/p/4553262.html ??先来看

大话多线程散篇一

1.进程:在系统中正在运行的一个应用程序 线程:一个进程要想执行任务必须有线程(每一个进程至少有一条进程) 2.主线程:显示.刷新UI界面,处理UI事件,与用户交互的都是主线程 二.  多线程的几种方式(面试常问)      1.Pthread:一套通用的多线程API,使用于UNix\Linux\Window等系统,跨平台,使用难度大,运用c语言,程序员自己管理生命周期. 2.NSthread:使用更加面向对象,简单易用,可直接操作线程对象,OC语言,程序员半管理,只用管理创建,不担心释放. 3

Linux多线程编程-互斥锁

互斥锁 多线程编程中,(多线程编程)可以用互斥锁(也称互斥量)可以用来保护关键代码段,以确保其独占式的访问,这有点像二进制信号量.POSIX互斥锁相关函数主要有以下5个: #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); int pthread_mutex_destroy(pthread_mutex_t *mutex); int p