多线程的使用

 

通过NSThread方式开辟线程三种方式

//1.alloc init,手动开启|能够对线程进行更加详细的设置
-(void)createNewThread1
{
    //1.创建线程
    /*
     第一个参数:目标对象  self
     第二个参数:要调用的方法的名称
     第三个参数:要调用方法需要传递的参数<最多传递一个参数,不传nil
     */

   MSHThread *threadA =  [[MSHThread alloc]initWithTarget:self selector:@selector(task) object:nil];

    //设置线程的属性
    threadA.name = @"线程A";         //设置线程的名称
    threadA.threadPriority = 1.0;   //设置线程的优先级,优先级取值范围为0.0~1.0 最高为1.0

    //2.启动线程
    [threadA start];
    self.threadA = threadA;

    /////////在创建两条线程////////////

    MSHThread *threadB =  [[MSHThread alloc]initWithTarget:self selector:@selector(task) object:nil];
    threadB.name = @"线程B";
    [threadB start];

    MSHThread *threadC =  [[MSHThread alloc]initWithTarget:self selector:@selector(task) object:nil];
    threadC.name = @"线程C";
    threadC.threadPriority = 0.1;
    [threadC start];
}
分离方式创建线程
//2.分离出一条新的线程,自动开启|不能够对线程进行更加详细的设置
-(void)createNewThread2
{
    //分离出一条新的线程
    /*
     第一个参数:要调用的方法
     第二个参数:目标对象  self
     第三个参数:要调用方法需要传递的参数
     */
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"分离出一条新的线程"];
}

//3.开启一条后台线程,自动开启|不能够对线程进行更加详细的设置
-(void)createNewThread3
{
    //开启一条后台线程 开后台线程的方式
    [self performSelectorInBackground:@selector(run:) withObject:@"开启一条后台线程"];
}

//线程生命周期:当任务执行完毕之后,线程对象会被销毁
-(void)task
{
  耗时操作放进线程
    for (NSInteger i =0; i<100; i++) {
         NSLog(@"%zd---task----%@",i,[NSThread currentThread].name);
    }
}

-(void)run:(NSString *)param
{
    NSLog(@"run---%@---%@",[NSThread currentThread],param);
}

线程的状态接创建跟跟销毁

启动线程
- (void)start;
// 进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态

阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 进入阻塞状态

强制停止线程
+ (void)exit;
// 进入死亡状态

注意:一旦线程停止(死亡)了,就不能再次开启任务

线程安全

#import "ViewController.h"

@interface ViewController ()
/** 售票员A*/
@property (nonatomic ,strong)NSThread *threadA;
/** 售票员B*/
@property (nonatomic ,strong)NSThread *threadB;
/** 售票员C*/
@property (nonatomic ,strong)NSThread *threadC;
/** 总票数*/
@property (nonatomic ,assign)NSInteger totalTickets;

@end

@implementation ViewController

-(void)viewDidLoad
{
     self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(sale) object:nil];
    self.threadA.name = @"售票员A";

     self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(sale) object:nil];
    self.threadB.name = @"售票员B";

     self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(sale) object:nil];
    self.threadC.name = @"售票员C";

    //设置100
    self.totalTickets = 100;

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

    [self.threadC start];

}

-(void)sale
{
    //int i = 0;
    //查看余票的数量,如有有name就卖出去一张,如果没有就告诉用户今年别回家了
    while (1) {// 多条线程访问一个资源,此处加锁
           @synchronized(self) {
        //锁对象:要求时唯一的

            NSInteger count = self.totalTickets;
            if (count >0) {

                [NSThread sleepForTimeInterval:0.01];
                self.totalTickets = count - 1;
                NSLog(@"%@卖出去了一张票,还剩下%zd张票",[NSThread currentThread].name,self.totalTickets);
            }else
            {
                NSLog(@"今年别回家了");
                break;
            }
        }
    }
}

多线程的安全隐患

l资源共享


p1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源


p比如多个线程访问同一个对象、同一个变量、同一个文件


l当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题

解决的方案

l互斥锁使用格式

@synchronized(锁对象) { // 需要锁定的代码  }

注意:锁定1份代码只用1把锁,用多把锁是无效的

l互斥锁的优缺点

p优点:能有效防止因多线程抢夺资源造成的数据安全问题

p缺点:需要消耗大量的CPU资源

p

l互斥锁的使用前提:多条线程抢夺同一块资源

p

l相关专业术语:线程同步

p线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务)

p互斥锁,就是使用了线程同步技术

原子和非原子属性

lOC在定义属性时有nonatomic和atomic两种选择

patomic:原子属性,为setter方法加锁(默认就是atomic)

pnonatomic:非原子属性,不会为setter方法加锁

 

线程之间通信

//演示线程间通信
-(void)download3
{
    //1.获得下载图片的url
    在子线程方法中进行耗时操作
    NSURL *url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/zhidao/pic/item/42166d224f4a20a4884b622491529822730ed0f8.jpg"];

    //2.下载图片的二进制数据到本地
    NSData *imageData = [NSData dataWithContentsOfURL:url];

    //3.把二进制数据转换为image
    UIImage *image = [UIImage imageWithData:imageData];

    NSLog(@"下载图片---%@",[NSThread currentThread]);

    //4.回到主线程刷新UI
    /*
     第一个参数:要调用的方法
     第二个参数:要传递的参数
     第三个参数:要不要继续等到调用方法执行完毕
     */回主线程的三种方式
    //[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
    //[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];

    //线程间通信的简便方法
    [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

    NSLog(@"---------");
}

-(void)showImage:(UIImage *)image
{  刷新UI
//    [NSThread sleepForTimeInterval:2.0];
     NSLog(@"刷新UI---%@",[NSThread currentThread]);
     self.imageView.image = image;
}

通过GDC方式开辟线程(C语言)

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    //[self performSelectorInBackground:@selector(syncMain) withObject:nil];
    [self asyncConcurrent];
}
异步:只决定具有开辟线程

同步:不具备开辟线程的能力 

串行:队列里的任务是有顺序的执行

并行:队列里的任务是并发执行,没有循序注意:并行队列只在异步函数中有效
//异步函数+并发队列:会开线程,开多条线程,任务并发执行
-(void)asyncConcurrent
{
    //创建队列,保持任务,安排|调度任务
    /*
     第一个参数:C语言的字符串,设置队列的标签
     第二个参数:队列的类型
        DISPATCH_QUEUE_SERIAL:串行队列
        DISPATCH_QUEUE_CONCURRENT:并发队列
     */
    dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);

    NSLog(@"---start----");
    //异步函数,封装任务,添加任务到队列中
    //异步函数:不需要等待当前代码执行完毕,就可以执行后面的代码
    //同步函数:要等到当前代码执行完毕,才能继续往下执行

    /*
     第一个参数:队列
     第二个参数:
     */
    dispatch_async(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 4---%@",[NSThread currentThread]);
    });

     NSLog(@"---end----");
}

//异步函数+串行队列:会开线程,1条线程,任务串行执行
-(void)asyncSerial
{
    //创建队列,保持任务,安排|调度任务
    /*
     第一个参数:C语言的字符串,设置队列的标签
     第二个参数:队列的类型
     DISPATCH_QUEUE_SERIAL:串行队列
     DISPATCH_QUEUE_CONCURRENT:并发队列
     */
    dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);

    //异步函数,封装任务,添加任务到队列中
    /*
     第一个参数:队列
     第二个参数:
     */
    dispatch_async(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });
}

//同步函数+并发队列:不会开线程,任务串行执行的
-(void)syncConcurrent
{
    //创建队列,保持任务,安排|调度任务
    /*
     第一个参数:C语言的字符串,设置队列的标签
     第二个参数:队列的类型
     DISPATCH_QUEUE_SERIAL:串行队列
     DISPATCH_QUEUE_CONCURRENT:并发队列
     */
   // dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);

    //获得全局并发队列,默认存在,特殊的并发队列
    //第一个参数:队列的优先级 DISPATCH_QUEUE_PRIORITY_DEFAULT == 0
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    NSLog(@"---start----");

    //同步函数,封装任务,添加任务到队列中
    /*
     第一个参数:队列
     第二个参数:
     */
    dispatch_sync(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });

    NSLog(@"---end----");
}

//同步函数+串行队列:不会开线程,任务串行执行的
-(void)syncSerial
{
    //创建队列,保持任务,安排|调度任务
    /*
     第一个参数:C语言的字符串,设置队列的标签
     第二个参数:队列的类型
     DISPATCH_QUEUE_SERIAL:串行队列
     DISPATCH_QUEUE_CONCURRENT:并发队列
     */
    dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);

    //同步函数,封装任务,添加任务到队列中
    /*
     第一个参数:队列
     第二个参数:
     */
    dispatch_sync(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });
}

//异步函数+主队列:不会开线程,任务串行执行的
-(void)asyncMain
{
    //1.获得主队列
    //特点:凡是放在主队列中的任务都在主线程中执行
    dispatch_queue_t queue =  dispatch_get_main_queue();

    //2.异步函数,封装任务,添加任务到队列中
    dispatch_async(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });

}

//同步函数+主队列:死锁
//主队列特点:如果发现主线程当前正在执行代码(任务),那么主队列将不会调度队列里的任务,直到主线程的任务执行完毕
-(void)syncMain
{
    //1.获得主队列
    //特点:凡是放在主队列中的任务都在主线程中执行// 全局主队列队列都会在主线程中执行,有序的,不能用同步函数执行
    dispatch_queue_t queue =  dispatch_get_main_queue();

    NSLog(@"------start----");
    //2.同步函数,封装任务,添加任务到队列中
    dispatch_sync(queue, ^{
        NSLog(@"download 1---%@",[NSThread currentThread]);

    });

    dispatch_sync(queue, ^{
        NSLog(@"download 2---%@",[NSThread currentThread]);
    });

    dispatch_sync(queue, ^{
        NSLog(@"download 3---%@",[NSThread currentThread]);
    });

    NSLog(@"------end----");
}

CDG中线程的同步

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //使用异步函数+并发队列开线程现在图片
    dispatch_async(queue, ^{

        NSLog(@"download----%@",[NSThread currentThread]);

        NSURL *url = [NSURL URLWithString:@"http://www.chinanews.com/cr/2014/0108/1576296051.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];

        //回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
           NSLog(@"UI----%@",[NSThread currentThread]);
            self.imageView.image = image;
        });
    });
}

GCD中常用的函数

#pragma mark ----------------------
#pragma mark Events
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self apply];

//    MSHPerson *p1 = [[MSHPerson alloc]init];
//    MSHPerson *p2 = [[MSHPerson alloc]init];
//    NSLog(@"%@---%@",p1.books,p2.books);
}

#pragma mark ----------------------
#pragma Methods
//延迟执行
-(void)delay
{
    NSLog(@"---start---");
    //延迟执行
    //[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];

    //[self performSelector:@selector(task) withObject:nil afterDelay:3.0];

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //GCD延迟执行
    /*
     第一个参数:表示从什么时候开始计时 DISPATCH_TIME_NOW:现在
     第二个参数:间隔的时间
     第三个参数:队列,决定block在哪个线程中调用,只有当队列是主队列的时候才在主线程调用
     第四个参数:
     */
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"----GCD---%@",[NSThread currentThread]);
    });
}

//栅栏函数
-(void)barrier
{
    //1.创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("www.520it", DISPATCH_QUEUE_CONCURRENT);

    //2.使用异步函数添加任务
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download 1--%zd-%@",i,[NSThread currentThread]);
        }

    });

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download 2--%zd-%@",i,[NSThread currentThread]);
        }
    });

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download 3--%zd-%@",i,[NSThread currentThread]);
        }
    });

    //栅栏函数:控制队列中任务的执行顺序,前面的所有任务执行完毕之后执行栅栏函数,自己执行完毕之后再之后后面的任务
    dispatch_barrier_async(queue, ^{
        NSLog(@"++++++++++++++++++++++++++");
    });

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download 4--%zd-%@",i,[NSThread currentThread]);
        }
    });

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"download 5--%zd-%@",i,[NSThread currentThread]);
        }
    });
}

//一次性代码
/*保证在整个程序运行过程中执行一次*/
-(void)once
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"---once---");
    });
}

//普通遍历和快速迭代比较
-(void)forAndApply
{
//    for (NSInteger i = 0; i<10; i++) {
//        NSLog(@"%zd----%@",i,[NSThread currentThread]);
//    }

    //1.创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("www.520it", DISPATCH_QUEUE_CONCURRENT);

    /*
     第一个参数:遍历的次数
     第二个参数:队列,决定block在哪个线程调用,并发队列
     第三个参数:索引
     */
    dispatch_apply(10, queue, ^(size_t index) {
          NSLog(@"%zd----%@",index,[NSThread currentThread]);
    });
}

//普通遍历剪切文件
-(void)moveFile
{
    //1.拿到文件夹的路径
    NSString *from = @"/Users/xmg/Desktop/from";

    //2.拿到目标文件夹的路径
    NSString *to = @"/Users/xmg/Desktop/to";

    //3.拿到该文件夹下面所有的文件
    NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
   // NSLog(@"%@",subPaths);

    NSInteger count = subPaths.count;
    //4.遍历数组
    for (NSInteger i = 0; i<count; i++) {

        //4.0 获得文件的名称
        NSString *fileName = subPaths[i];

        //4.1 拼接文件的全路径
        //stringByAppendingPathComponent:在拼接之前添加/
        NSString *fromFullPath = [from stringByAppendingPathComponent:fileName];

        //4.2 剪切到什么地方
        NSString *toFullPath = [to stringByAppendingPathComponent:fileName];

        NSLog(@"%@---%@---%@",fromFullPath,toFullPath,[NSThread currentThread]);
        //4.3 执行剪切操作
        /*
         第一个参数:文件的路径
         第二个参数:目标路径
         第三个参数:
         */
        NSError *error = nil;
        [[NSFileManager defaultManager] moveItemAtPath:fromFullPath toPath:toFullPath error:&error];
    }
}

//快速迭代剪切文件
-(void)apply
{

    //1.拿到文件夹的路径
    NSString *from = @"/Users/xmg/Desktop/from";

    //2.拿到目标文件夹的路径
    NSString *to = @"/Users/xmg/Desktop/to";

    //3.拿到该文件夹下面所有的文件
    NSArray *subPaths = [[NSFileManager defaultManager] subpathsAtPath:from];
    // NSLog(@"%@",subPaths);

    NSInteger count = subPaths.count;
    //4.遍历数组
    dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index) {
        //4.0 获得文件的名称
        NSString *fileName = subPaths[index];

        //4.1 拼接文件的全路径
        //stringByAppendingPathComponent:在拼接之前添加/
        NSString *fromFullPath = [from stringByAppendingPathComponent:fileName];

        //4.2 剪切到什么地方
        NSString *toFullPath = [to stringByAppendingPathComponent:fileName];

        NSLog(@"%@---%@---%@",fromFullPath,toFullPath,[NSThread currentThread]);
        //4.3 执行剪切操作
        /*
         第一个参数:文件的路径
         第二个参数:目标路径
         第三个参数:
         */
        NSError *error = nil;
        [[NSFileManager defaultManager] moveItemAtPath:fromFullPath toPath:toFullPath error:&error];
    });
}

//延迟执行的测试方法
-(void)task
{
    NSLog(@"---%s",__func__);
}
@end
时间: 2024-10-26 09:08:18

多线程的使用的相关文章

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Spring多线程

Spring是通过TaskExecutor任务执行器来实现多线程和并发编程的.使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor.而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步的支持,并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务. 实例代码: (1)配置类 package com.lwh.highlight_spring4.ch3.taskexecutor; /**

python进阶学习(一)--多线程编程

1. 多线程 概念:简单地说操作系统可以同时执行多个不用程序.例如:一边用浏览器上网,一边在听音乐,一边在用笔记软件记笔记. 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务"一起"执行(实际上总有一些任务不在执行,因为切换任务的熟度相当快,看上去一起执行而已) 并行:指的是任务数小于等于CPU核数,即任务真的是一起执行的. 2. 线程 概念:线程是进程的一个实体,是CPU调度和分派的基本单位. threading--单线程执行: 1 import ti

多线程的实现及其安全问题

一.进程和线程概述 1.进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动,简单来说开启一个程序就开启了一个进程: 如果开启多个进程,它们之间是由于CPU的时间片在相互的切换: 2.线程:开启一个进程的一个任务,对于多线程:每一个线程都在争夺CPU的执行权(CPU的执行权具有随机性): 如果一个程序的执行路径有多条,那么该线程是多线程;反之,就单线程线程:线程是依赖于进程存在的! 3.Jvm是多线程 -- 至少开启了两条线程 main方法 主线程 gc() 垃圾回收线程 二.多线程

多线程和多进程的区别与联系

1.单进程单线程:一个人在一个桌子上吃菜.2.单进程多线程:多个人在同一个桌子上一起吃菜.3.多进程单线程:多个人每个人在自己的桌子上吃菜. 多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了...此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢. 1.对于 Windows 系统来说,[开桌子]的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜.因此 Windows 多线程学习重点

Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

最近正在学习Python中的异步编程,看了一些博客后做了一些小测验:对比asyncio+aiohttp的爬虫和asyncio+aiohttp+concurrent.futures(线程池/进程池)在效率中的差异,注释:在爬虫中我几乎没有使用任何计算性任务,为了探测异步的性能,全部都只是做了网络IO请求,就是说aiohttp把网页get完就程序就done了. 结果发现前者的效率比后者还要高.我询问了另外一位博主,(提供代码的博主没回我信息),他说使用concurrent.futures的话因为我全

多线程(一)

这边来谈谈java中,我对对多线程的理解 在了解多线程前,先说说进程. 进程就是正在运行的应用程序.  当你打开任务管理器的时候,你就会发现很多的进程. 而我们要说的线程,就是依赖于进程而存在的,一个进程可以开启多个线程. Thread类 说到线程,就必须来说说Thread类. Thread类是说有线程的父类.具体请参见api 线程的创建以及执行(图解如下) 继承Thread类,或者实现rennable接口. 当继承了父类后,需要重写父类的run方法,这个run方法里面就写你要执行的代码,当这个

多线程下的单例-double check

话不多说直接上代码: public sealed class Singleton { private static Singleton _instance = null; // Creates an syn object. private static readonly object SynObject = new object(); Singleton() { } public static Singleton Instance { get { // Double-Checked Lockin

笔记:多线程

多线程程序在较低的层次上扩展了多任务的概念:一个程序同时执行多个任务,通常每个任务称为一个线程(thread),他是线程控制的简称,可以同时运行一个以上线程的程序称为多线程程序(multithreaded):多线程和多进程有哪些区别呢,本质的区别在于每个进程拥有自己的一整套变量,而线程则是共享数据,Java中启动一个线程的代码如下: // 线程任务的具体实现接口 ????public interface Runnable { public abstract void run(); ????} /

多线程

1.线程的概念? 多线程,就类似与操作系统中的多进程.简单的讲,就是可 以同时并发执行多个任务,处理多件事情.这与我们经常所 谓的边唱边跳,边说边做事一个道理.? 线程是一个轻量级的进程,一个进程中可以分为多个线程. 比起进程,线程所耗费的系统资源更少,切换更加容易 /* * 进程是操作系统中的一个任务,一个程序启动运行,就会创建 * 一个(或多个)进程. * 线程是轻量级的进程.进程会有自己独立的内存空间与资源.一个进程 * 下会存在一个(或多个)线程.线程为进程的执行单元.线程本身不含有 *