第9讲(多线程)
Java编程基础及应用(第2版)教学课件第9章Java多线程机制

现代操作系统可以同时管理 一个计算机系统中的多个进程, 即可以让计算机系统中的多个进 程轮流使用CPU资源。
§9.1.2 进程与线程
线程是比进程更小的执行 单位,一个进程在其执行过程 中,可以产生多个线程,形成 多条执行线索,每条线索,即 每个线程也有它自身的产生、 存在和消亡的过程。
例题1
§9.2.3 线程调度与优先级
处于就绪状态的线程首先进入就绪队列排队等候 CPU资源,同一时刻在就绪队列中的线程可能有多个。 Java虚拟机(JVM)中的线程调度器负责管理线程, 调度器把线程的优先级分为10个级别,分别用Thread 类中的类常量表示。
Java 调 度 器 的 任 务 是 使 高 优 先 级 的 线 程 能 始 终 运 行 , 一旦时间片有空闲,则使具有同等优先级的线程以轮流 的方式顺序使用时间片。
5.currentThread():该方法是Thread类中的类方法,可以用类名调用,该方法
返回当前正在使用CPU资源的线程。
6.interrupt() :一个占有CPU资源的线程可以让休眠的线程调用interrupt()方
法“吵醒”自己,即导致休眠的线程发生InterruptedException异常,从而结束休眠, 重新排队等待CPU资源。
例子5
例子5中有两个线程:会计和出纳,他俩共同拥有一个帐本。 他俩都可以使用saveOrTake(int amount)方法对帐本进行访问, 会计使用saveOrTake(int amount)方法时,向帐本上写入存钱记 录;出纳使用saveOrTake(int amount)方法时,向帐本写入取钱 记录。因此,当会计正在使用saveOrTake(int amount)时,出纳 被禁止使用,反之也是这样。
Java多线程详解——一篇文章搞懂Java多线程

Java多线程详解——⼀篇⽂章搞懂Java多线程⽬录1. 基本概念程序(program)程序是为完成特定任务、⽤某种语⾔编写的⼀组指令的集合。
即指⼀段静态的代码(还没有运⾏起来),静态对象。
进程(process)进程是程序的⼀次执⾏过程,也就是说程序运⾏起来了,加载到了内存中,并占⽤了cpu的资源。
这是⼀个动态的过程:有⾃⾝的产⽣、存在和消亡的过程,这也是进程的⽣命周期。
进程是系统资源分配的单位,系统在运⾏时会为每个进程分配不同的内存区域。
线程(thread)进程可进⼀步细化为线程,是⼀个程序内部的执⾏路径。
若⼀个进程同⼀时间并⾏执⾏多个线程,那么这个进程就是⽀持多线程的。
线程是cpu调度和执⾏的单位,每个线程拥有独⽴的运⾏栈和程序计数器(pc),线程切换的开销⼩。
⼀个进程中的多个线程共享相同的内存单元/内存地址空间——》他们从同⼀堆中分配对象,可以访问相同的变量和对象。
这就使得相乘间通信更简便、搞笑。
但索格线程操作共享的系统资源可能就会带来安全隐患(隐患为到底哪个线程操作这个数据,可能⼀个线程正在操作这个数据,有⼀个线程也来操作了这个数据v)。
配合JVM内存结构了解(只做了解即可)class⽂件会通过类加载器加载到内存空间。
其中内存区域中每个线程都会有虚拟机栈和程序计数器。
每个进程都会有⼀个⽅法区和堆,多个线程共享同⼀进程下的⽅法区和堆。
CPU单核和多核的理解单核的CPU是⼀种假的多线程,因为在⼀个时间单元内,也只能执⾏⼀个线程的任务。
同时间段内有多个线程需要CPU去运⾏时,CPU也只能交替去执⾏多个线程中的⼀个线程,但是由于其执⾏速度特别快,因此感觉不出来。
多核的CPU才能更好的发挥多线程的效率。
对于Java应⽤程序java.exe来讲,⾄少会存在三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。
如过发⽣异常时会影响主线程。
Java线程的分类:⽤户线程和守护线程Java的gc()垃圾回收线程就是⼀个守护线程守护线程是⽤来服务⽤户线程的,通过在start()⽅法前调⽤thread.setDaemon(true)可以吧⼀个⽤户线程变成⼀个守护线程。
python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)

python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon)前⾔今天⼩王请xiaoming和xiaowang吃⽕锅,吃完⽕锅的时候会有以下三种场景:场景⼀:⼩王(主)先吃完了,海海(客)和⽼王(客)还没吃完,这种场景会导致结账的⼈先⾛了,剩下两个⼩伙伴傻眼了。
场景⼆:⼩王(主)先吃完了,海海和⽼王还没吃饱,⼀起结账⾛⼈。
场景三:⼩王(主)先等海海和⽼王吃饱了,⼩编最后结账⼀起⾛⼈。
主线程与⼦线程场景⼀:主线程已经结束了,⼦线程还在跑1.我们把thread1.start()和thread2.start()称为两个⼦线程,写在外⾯的代码就是主线程了。
# -*- coding:utf-8 -*-import timeimport threadingdef chiHuoGuo(people):print("%s 吃⽕锅的⼩伙伴-⽺⾁:%s" % (time.ctime(),people))time.sleep(1)print("%s 吃⽕锅的⼩伙伴-鱼丸:%s" % (time.ctime(),people))class myThread(threading.Thread):def __init__(self, people, name):'''重写threading.Thread初始化内容'''threading.Thread.__init__(self)self.threadNmae = nameself.people = peopledef run(self):print("开始线程:" + self.threadNmae)chiHuoGuo(self.people)print("结束线程:" + self.threadNmae)if __name__ == "__main__":# 启动线程thread1 = myThread("xiaoming", "Thread-1")thread2 = myThread("xiaowang", "Thread-2")thread1.start()thread2.start()time.sleep(0.1)print("退出主线程:吃⽕锅,结账⾛⼈")守护线程setDaemon()场景⼆:主线程结束了,⼦线程必须也跟着结束1.主线程中,创建了⼦线程线程A和线程B,并且在主线程中调⽤了thread.setDaemon(),这个的意思是,把主线程设置为守护线程,这时候,要是主线程执⾏结束了,就不管⼦线程是否完成,⼀并和主线程退出.(敲⿊板:必须在start()⽅法调⽤之前设置,如果不设置为守护线程,程序会被⽆限挂起。
Java多线程技术PPT课件

❖ public Thread(Runnable target) ❖ public Thread(String name)
9
2. 如何实现多线程? 2.1 Thread类和Runnable接口
Thread类有3个有关线程优先级的常量:
❖ Thread.MIN_PRIORITY=1; ❖ Thread.MAX_PRIORITY=10; ❖ Thread.NORM_PRIORITY=5;
学习提纲
1
1. 程序、进程和线程 1.1 程序、进程和线程
程 序 ( Program ) 是能完成预定功能的静 态的指令序列。
2
பைடு நூலகம்
1. 程序、进程和线程 1.1 程序、进程和线程
为提高操作系统的并行性和资源利用率,提出了进程(Process)的概 念。简单地说进程是程序的一次执行,进程是动态的。
为解决此问题,又提出了线程(Thread)的概念。将资源分配和处理器 调度的基本单位分离,进程只是资源分配的单位,线程是处理器调度的 基本单位。一个进程包含多个并发的线程。一个进程中的线程只能使用进
程的资源和环境。线程只包含程序计数器、栈指针及堆栈,不包含进程地址
空 间 的 代 码 和 数 据 , 因 此 线 程 被 称 为 轻 质 进 程 ( Light Weight Process)。线程提高了系统的整体性能和效率。
正在执行的线程休眠(暂停执行)。
11
2. 如何实现多线程? 2.1 Thread类和Runnable接口
Runnable接口在ng包中,定义如下:
❖ public interface Runnable
Runnable接口中只包含一个抽象方法:
Java程序设计教程 第九章

9.1.2ava中,每个线程从创建到消亡为一个生 Java中,每个线程从创建到消亡为一个生 存周期,它将经历四个状态: (1)新建状态(New Thread Status )新建状态(New (2)可执行状态(Runnable) )可执行状态(Runnable) (3)阻塞状态(Blocked) )阻塞状态(Blocked) (4)消亡状态(Dead thread) )消亡状态(Dead thread)
9.1.2 线程的控制
4. 终止一个线程 在程序中不能任意终止一个线程,否则可能 造成严重的线程安全问题.一个线程的终止 必须靠run()方法的正常返回.当一个线程从 必须靠run()方法的正常返回.当一个线程从 run()方法返回后,它就进入消亡状态,再也 run()方法返回后,它就进入消亡状态,再也 不能被运行了.结束run()方法还有另一种途 不能被运行了.结束run()方法还有另一种途 径,那就是在run()方法中抛出了异常,如果 径,那就是在run()方法中抛出了异常,如果 这些异常没有被捕获,JVM将会终止该线程. 这些异常没有被捕获,JVM将会终止该线程.
9.1.1 线程的概念
与程序的顺序执行相对的是程序的并发执行, 即一组逻辑上互相独立的程序或程序段在执 行过程中,其执行时间在客观上互相重叠. 程序的并发执行可以分成两种情况:一种是 多道程序系统中多道程序的并发执行,此种 情况下实际上是宏观上(程序级)同时进行, 微观上(指令级)顺序执行的;另一种是在 某道程序段的几个程序片段中,包含着一部 分可以同时执行或顺序颠倒执行的代码.程 序的并发执行是实现多线程技术的基础.
9.1.1 线程的概念
线程与进程类似,是一段完成特定功能的代 码.它是程序中单个顺序的控制流,也是一 个进程内的基本调度单位.线程和进程一样 拥有独立的执行控制,并由操作系统负责调 度.同一进程可以包含多个线程,这些线程 共享属于该进程的一块内存空间和一组系统 资源;而线程自身的数据通常只有微处理器 的寄存器数据,以及一个供程序执行时使用 的堆栈.系统在产生一个线程,或者在各个 线程之间切换时,负担要比进程小得多.此 外,由于线程只是在单个进程的作用域内活 动,所以线程间的通信也比进程简单.线程 的实现要依靠操作系统,现代操作系统一般 都支持线程技术.
多线程实现的几种方式

多线程实现的⼏种⽅式多线程实现⼀共有四种⽅式,如下图:- pthread的使⽤ - 定义pthreadtypedef __darwin_pthread_t pthread_t; - 创建pthreadint pthread_create(pthread_t * __restrict, const pthread_attr_t * __restrict,void *(*)(void *), void * __restrict); - 范例void * run(void *param){for (NSInteger i = 0; i<50000; i++) {NSLog(@"------buttonClick---%zd--%@", i, [NSThread currentThread]);}return NULL;}- (IBAction)buttonClick:(id)sender {pthread_t thread;pthread_create(&thread, NULL, run, NULL);pthread_t thread2;pthread_create(&thread2, NULL, run, NULL);}- NSThread - 创建和启动线程NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];[thread start]; - 主线程相关⽤法+ (NSThread *)mainThread; // 获得主线程- (BOOL)isMainThread; // 是否为主线程+ (BOOL)isMainThread; // 是否为主线程 - 获取当前线程NSThread *current = [NSThread currentThread]; - 线程的名字- (void)setName:(NSString *)n;- (NSString *)name; - 其它⽅式创建线程 - 创建线程后⾃动启动线程[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil]; - 隐式创建并启动线程[self performSelectorInBackground:@selector(run) withObject:nil]; - 上述2种创建线程⽅式的优缺点 - 优点:简单快捷 - 缺点:⽆法对线程进⾏更详细的设置 - 线程的状态NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];[thread start]; - 阻塞(暂停)线程+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;// 进⼊阻塞状态 - 强制停⽌线程+ (void)exit;// 进⼊死亡状态注意:⼀旦线程停⽌(死亡)了,就不能再次开启任务 - 多线程的隐患 - 资源共享 - 1块资源可能会被多个线程共享,也就是多个线程可能会访问同⼀块资源 - ⽐如多个线程访问同⼀个对象、同⼀个变量、同⼀个⽂件 - 当多个线程访问同⼀块资源时,很容易引发数据错乱和数据安全问题 - 解决⽅法:互斥锁 - 互斥锁使⽤格式@synchronized(锁对象) { // 需要锁定的代码 }注意:锁定1份代码只⽤1把锁,⽤多把锁是⽆效的 - 互斥锁的优缺点 - 优点:能有效防⽌因多线程抢夺资源造成的数据安全问题 - 缺点:需要消耗⼤量的CPU资源 - 互斥锁的使⽤前提:多条线程抢夺同⼀块资源 - 相关专业术语:线程同步 - 线程同步的意思是:多条线程在同⼀条线上执⾏(按顺序地执⾏任务) - 互斥锁,就是使⽤了线程同步技术 - 原⼦和⾮原⼦属性 - OC在定义属性时有nonatomic和atomic两种选择 - atomic:原⼦属性,为setter⽅法加锁(默认就是atomic) - nonatomic:⾮原⼦属性,不会为setter⽅法加锁 - nonatomic和atomic对⽐ - atomic:线程安全,需要消耗⼤量的资源 - nonatomic:⾮线程安全,适合内存⼩的移动设备 - iOS开发的建议 - 所有属性都声明为nonatomic - 尽量避免多线程抢夺同⼀块资源 - 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减⼩移动客户端的压⼒- GCD的使⽤ - 什么是GCD - 全称是Grand Central Dispatch,可译为“⽜逼的中枢调度器” - 纯C语⾔,提供了⾮常多强⼤的函数 - GCD的优势 - GCD是苹果公司为多核的并⾏运算提出的解决⽅案 - GCD会⾃动利⽤更多的CPU内核(⽐如双核、四核) - GCD会⾃动管理线程的⽣命周期(创建线程、调度任务、销毁线程) - 程序员只需要告诉GCD想要执⾏什么任务,不需要编写任何线程管理代码 - GCD中有2个核⼼概念 - 任务:执⾏什么操作 - 队列:⽤来存放任务 - GCD的使⽤就2个步骤 - 定制任务 - 确定想做的事情 - 将任务添加到队列中 - GCD会⾃动将队列中的任务取出,放到对应的线程中执⾏ - 任务的取出遵循队列的FIFO原则:先进先出,后进后出 - GCD中有2个⽤来执⾏任务的常⽤函数 - ⽤同步的⽅式执⾏任务// queue:队列 block:任务dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); - ⽤异步的⽅式执⾏任务dispatch_async(dispatch_queue_t queue, dispatch_block_t block); - 同步和异步的区别 - 同步:只能在当前线程中执⾏任务,不具备开启新线程的能⼒ - 异步:可以在新的线程中执⾏任务,具备开启新线程的能⼒ - GCD中还有个⽤来执⾏任务的函数,在前⾯的任务执⾏结束后它才执⾏,⽽且它后⾯的任务等它执⾏完成之后才会执⾏:// 这个queue不能是全局的并发队列dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); - 队列的类型 - GCD的队列可以分为2⼤类型 - 并发队列(Concurrent Dispatch Queue) - 可以让多个任务并发(同时)执⾏(⾃动开启多个线程同时执⾏任务) - 并发功能只有在异步(dispatch_async)函数下才有效 - 串⾏队列(Serial Dispatch Queue) - 让任务⼀个接着⼀个地执⾏(⼀个任务执⾏完毕后,再执⾏下⼀个任务) - 并发队列 - ⾃⼰创建的 - 全局 - 串⾏队列 - 主队列 - ⾃⼰创建的 - 同步和异步主要影响:能不能开启新的线程 - 同步:只是在当前线程中执⾏任务,不具备开启新线程的能⼒ - 异步:可以在新的线程中执⾏任务,具备开启新线程的能⼒ - 并发和串⾏主要影响:任务的执⾏⽅式 - 并发:允许多个任务并发(同时)执⾏ - 串⾏:⼀个任务执⾏完毕后,再执⾏下⼀个任务 - 并发队列// 使⽤dispatch_queue_create函数创建队列dispatch_queue_tdispatch_queue_create(const char *label, // 队列名称dispatch_queue_attr_t attr); // 队列的类型// 创建并发队列dispatch_queue_t queue = dispatch_queue_create("com.samyang.queue", DISPATCH_QUEUE_CONCURRENT); // GCD默认已经提供了全局的并发队列,供整个应⽤使⽤,可以⽆需⼿动创建使⽤dispatch_get_global_queue函数获得全局的并发队列dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, // 队列的优先级unsigned long flags); // 此参数暂时⽆⽤,⽤0即可// 获得全局并发队列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 全局并发队列的优先级#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // ⾼#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 - 串⾏队列// GCD中获得串⾏有2种途径// 使⽤dispatch_queue_create函数创建串⾏队列// 创建串⾏队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)dispatch_queue_t queue = dispatch_queue_create("com.samyang.queue", NULL);/*使⽤主队列(跟主线程相关联的队列)主队列是GCD⾃带的⼀种特殊的串⾏队列放在主队列中的任务,都会放到主线程中执⾏使⽤dispatch_get_main_queue()获得主队列*/dispatch_queue_t queue = dispatch_get_main_queue(); - 各种队列的执⾏效果- 注意:使⽤sync函数往当前串⾏队列中添加任务,会卡住当前的串⾏队列 - 延时执⾏ - iOS常见的延时执⾏// 调⽤NSObject的⽅法[self performSelector:@selector(run) withObject:nil afterDelay:2.0];// 2秒后再调⽤self的run⽅法// 使⽤GCD函数dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后执⾏这⾥的代码...});// 使⽤NSTimer[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO]; - ⼀次性代码(⽐如说单例模式singleton)// 使⽤dispatch_once函数能保证某段代码在程序运⾏过程中只被执⾏1次static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{// 只执⾏1次的代码(这⾥⾯默认是线程安全的)}); - 快速迭代// 使⽤dispatch_apply函数能进⾏快速迭代遍历dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){// 执⾏10次代码,index顺序不确定}); - 队列组 -有这么1种需求 - ⾸先:分别异步执⾏2个耗时的操作 - 其次:等2个异步操作都执⾏完毕后,再回到主线程执⾏操作// 如果想要快速⾼效地实现上述需求,可以考虑⽤队列组dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执⾏1个耗时的异步操作});dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// 执⾏1个耗时的异步操作});dispatch_group_notify(group, dispatch_get_main_queue(), ^{// 等前⾯的异步操作都执⾏完毕后,回到主线程...});- NSOperationNSOperationQueue的队列类型主队列[NSOperationQueue mainQueue]凡是添加到主队列中的任务(NSOperation),都会放到主线程中执⾏⾮主队列(其他队列)[[NSOperationQueue alloc] init]同时包含了:串⾏、并发功能添加到这种队列中的任务(NSOperation),就会⾃动放到⼦线程中执⾏NSOperation的作⽤配合使⽤NSOperation和NSOperationQueue也能实现多线程编程NSOperation和NSOperationQueue实现多线程的具体步骤先将需要执⾏的操作封装到⼀个NSOperation对象中然后将NSOperation对象添加到NSOperationQueue中系统会⾃动将NSOperationQueue中的NSOperation取出来将取出的NSOperation封装的操作放到⼀条新线程中执⾏NSOperation的⼦类NSOperation是个抽象类,并不具备封装操作的能⼒,必须使⽤它的⼦类使⽤NSOperation⼦类的⽅式有3种NSInvocationOperationNSBlockOperation⾃定义⼦类继承NSOperation,实现内部相应的⽅法NSInvocationOperation创建NSInvocationOperation对象- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;调⽤start⽅法开始执⾏操作- (void)start;⼀旦执⾏操作,就会调⽤target的sel⽅法注意默认情况下,调⽤了start⽅法后并不会开⼀条新线程去执⾏操作,⽽是在当前线程同步执⾏操作只有将NSOperation放到⼀个NSOperationQueue中,才会异步执⾏操作NSBlockOperation创建NSBlockOperation对象+ (id)blockOperationWithBlock:(void (^)(void))block; - 通过addExecutionBlock:⽅法添加更多的操作- (void)addExecutionBlock:(void (^)(void))block;注意:只要NSBlockOperation封装的操作数 > 1,就会异步执⾏ - NSOperationQueue - NSOperationQueue的作⽤ - NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执⾏的 - 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会⾃动异步执⾏NSOperation中的操作 - 添加操作到NSOperationQueue中- (void)addOperation:(NSOperation *)op;- (void)addOperationWithBlock:(void (^)(void))block; - 最⼤并发数 - 什么是并发数 - 同时执⾏的任务数 - ⽐如,同时开3个线程执⾏3个任务,并发数就是3 - 最⼤并发数的相关⽅法- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt; - 队列的取消、暂停、恢复取消队列的所有操作- (void)cancelAllOperations;- 提⽰:也可以调⽤NSOperation的- (void)cancel⽅法取消单个操作 - 暂停和恢复队列- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列- (BOOL)isSuspended; - 操作优先级 设置NSOperation在queue中的优先级,可以改变操作的执⾏优先级- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p; - 优先级的取值NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8 - 操作依赖 - NSOperation之间可以设置依赖来保证执⾏顺序 - ⽐如⼀定要让操作A执⾏完后,才能执⾏操作B,可以这么写[operationB addDependency:operationA]; // 操作B依赖于操作A - 可以在不同queue的NSOperation之间创建依赖关系 注意:不能相互依赖,⽐如A依赖B,B依赖A - 操作的监听 - 可以监听⼀个操作的执⾏完毕- (void (^)(void))completionBlock;- (void)setCompletionBlock:(void (^)(void))block; - ⾃定义NSOperation - ⾃定义NSOperation的步骤很简单 - 重写- (void)main⽅法,在⾥⾯实现想执⾏的任务 - 重写- (void)main⽅法的注意点 - ⾃⼰创建⾃动释放池(因为如果是异步操作,⽆法访问主线程的⾃动释放池) - 经常通过- (BOOL)isCancelled⽅法检测操作是否被取消,对取消做出响应。
第9章-C#程序设计教程(第2版)-蒙祖强-清华大学出版社
本:
构造函数创建的线程关联没
有参数的方法
public Thread(ThreadStart start)
public Thread(ParameterizedThreadStart start) ——每个线程都必须关联一个无返回类型的方法(称为线程方 其法中),参如数果关sta联rt是的T方h法re无ad参St数art,类则型用或第Pa一r构a个m造构e函te数造r创i函ze建d数的T创线hr程建ea关线d联S程带ta;rt 类如型果的关变联量的。 方这法两带种一委个托参类数型,的则声用明第如二下个一:构个造ob函jec数t类创型参建数线的程方。法
进程是由多个线程组成,即线程是进程的一个组成部分。
线程的划分尺度小,具有较高的并发效率。
进程独占相应的内存和资源(其他进程不能使用),线程则是 共享进程所拥有的内存和资源(其他线程也可以使用),从而极 大地提高运行效率。
进程提供多个线程执行控制,而每个线程只能有一个运行入口、 顺序执行序列和出口(“线序”执行)。
让当前线程 睡眠100毫秒
}
}
9.1 一个简单的多线程应用程序 C#程序设计教程——蒙祖强编著
class B
{ public static void g()
{ for (int i = 0; i < 10; i++)
{ Console.WriteLine("g()在输出:{0}", A.n);
A.n++; Thread.Sleep(100); }
第9章 多线程
本章内容
9.1 一个简单的多线程应用程序 9.2 线程及其实现方法 9.3 线程的同步控制 9.4 线程池 9.5 线程对控件的访问
多线程工作原理
多线程工作原理
多线程是指在一个程序中同时运行多个线程,每个线程都可以执行不同的任务。
多线程的工作原理是操作系统分配给每个线程一个时间片,使得每个线程按照一定的顺序交替执行,从而实现并发执行的效果。
具体来说,多线程的工作原理包括以下几个方面:
1. 线程调度:操作系统根据一定的调度算法,给每个线程分配一个时间片,使得每个线程都能得到执行的机会。
线程调度可以采用抢占式调度或协作式调度。
2. 上下文切换:当一个线程的时间片用完或者被其他高优先级的线程抢占时,操作系统会进行上下文切换,将当前线程的状态保存下来,并加载下一个要执行的线程的状态。
这个过程包括保存和恢复线程的寄存器、堆栈和程序计数器等状态信息。
3. 共享资源的互斥访问:多个线程在同时访问共享资源时可能产生冲突,为了避免数据不一致的问题,需要采取同步机制,如互斥锁、条件变量等,来保证只有一个线程可以访问共享资源。
4. 线程间的通信:多个线程之间通常需要进行数据交换和同步,可以通过共享内存、消息队列、管道、信号量等机制来实现线程间的通信。
总之,多线程的工作原理是操作系统通过调度和切换线程的方
式,使得多个线程可以并发执行,并通过同步和通信机制来保证线程之间的正确交互。
C语言多线程操作
C语⾔多线程操作多线程是多任务处理的⼀种特殊形式,多任务处理允许让电脑同时运⾏两个或两个以上的程序。
⼀般情况下,两种类型的多任务处理:基于进程和基于线程。
基于进程的多任务处理是程序的并发执⾏。
基于线程的多任务处理是同⼀程序的⽚段的并发执⾏。
多线程程序包含可以同时运⾏的两个或多个部分。
这样的程序中的每个部分称为⼀个线程,每个线程定义了⼀个单独的执⾏路径。
本教程假设您使⽤的是 Linux 操作系统,我们要使⽤ POSIX 编写多线程 C++ 程序。
POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可⽤,⽐如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。
下⾯的程序,我们可以⽤它来创建⼀个POSIX 线程:#include <pthread.h>pthread_create (thread, attr, start_routine, arg)在这⾥,pthread_create 创建⼀个新的线程,并让它可执⾏。
下⾯是关于参数的说明:参数描述thread指向线程标识符指针。
attr⼀个不透明的属性对象,可以被⽤来设置线程属性。
您可以指定线程属性对象,也可以使⽤默认值 NULL。
start_routine线程运⾏函数起始地址,⼀旦线程被创建就会执⾏。
arg运⾏函数的参数。
它必须通过把引⽤作为指针强制转换为 void 类型进⾏传递。
如果没有传递参数,则使⽤ NULL。
创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。
使⽤下⾯的程序,我们可以⽤它来终⽌⼀个 POSIX 线程:#include <pthread.h>pthread_exit (status)在这⾥,pthread_exit ⽤于显式地退出⼀个线程。
通常情况下,pthread_exit() 函数是在线程完成⼯作后⽆需继续存在时被调⽤。
[Delphi]多线程编程(9)认识等待函数 WaitForSingleObject
一下子跳到等待函数WaitForSingleObject, 是因为下面的Mutex、Semaphore、Eve nt、WaitableTimer 等同步手段都要使用这个函数; 不过等待函数可不止WaitForSingl eObject 它一个, 但它最简单.function WaitForSingleObject(hHandle: THandle; {要等待的对象句柄}dwMilliseconds: DWORD {等待的时间, 单位是毫秒}): DWORD; stdcall; {返回值如下:}WAIT_OBJECT_0 {等着了, 本例中是: 等的那个进程终于结束了}WAIT_TIMEOUT {等过了点(你指定的时间), 也没等着}WAIT_ABANDONED {好不容易等着了, 但人家还是不让咱执行; 这一般是互斥对象}//WaitForSingleObject 的第二个参数一般给常数值 INFINITE, 表示一直等下去, 死等.WaitForSingleObject 等待什么? 在多线程里就是等待另一个线程的结束, 快来执行自己的代码; 不过它可以等待的对象可不止线程; 这里先来一个等待另一个进程结束的例子,运行效果图:代码文件:unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);end;varForm1: TForm1;implementation{$R *.dfm}varhProcess: THandle; {进程句柄}{等待一个指定句柄的进程什么时候结束}function MyThreadFun(p: Pointer): DWORD; stdcall;beginif WaitForSingleObject(hProcess, INFINITE) = WAIT_OBJECT _0 thenForm1.Text := Format('进程 %d 已关闭', [hProcess]);Result := 0;end;{启动一个进程, 并建立新线程等待它的结束}procedure TForm1.Button1Click(Sender: TObject);varpInfo: TProcessInformation;sInfo: TStartupInfo;Path: array[0..MAX_PATH-1] of Char;ThreadID: DWORD;begin{先获取记事本的路径}GetSystemDirectory(Path, MAX_PATH);StrCat(Path, '\notepad.exe');{用 CreateProcess 打开记事本并获取其进程句柄, 然后建立线程监视} FillChar(sInfo, SizeOf(sInfo), 0);if CreateProcess(Path, nil, nil, nil, False, 0, nil, nil, sInfo, pInfo) thenbeginhProcess := pInfo.hProcess; {获取进程句柄}Text := Format('进程 %d 已启动', [hProcess]);CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID); {建立线程监视}end;end;end.。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
多线程机制
1、几个概念 、 程序:是一段静态的代码。 程序:是一段静态的代码。 进程:被运行的程序,是程序的一次动态执行过程, 进程:被运行的程序,是程序的一次动态执行过程, 它对应从代码加载、执行到执行完毕的一个完整过程。 它对应从代码加载、执行到执行完毕的一个完整过程。 这个过程也是进程本身从产生、发展到消亡的过程。 这个过程也是进程本身从产生、发展到消亡的过程。 多任务操作系统: 分时机制。 多任务操作系统:CPU分时机制。 分时机制 线程:在一个程序内包括的多个独立的小任务。 线程:在一个程序内包括的多个独立的小任务。能 够同时运行。与进程的区别是共享相同的数据。 够同时运行。与进程的区别是共享相同的数据。线程 使程序同时运行多个子任务,具有灵活的处理能力。 使程序同时运行多个子任务,具有灵活的处理能力。 [例] 未使用多线程技术的记数程序。 例 未使用多线程技术的记数程序。
class CounterSubTask extends Thread { ... public void run( ) { ... } }
public class CounterMultiThread { public static void main(String [ ] args) { ... } }
2、创建线程 、 实现线程的前提是对程序进行子任务划分。 实现线程的前提是对程序进行子任务划分。 [例] 使用线程技术的记数程序。 例 使用线程技术的记数程序。 在该例中有两个线程,一个用于记数, 在该例中有两个线程,一个用于记数,一个用于事 件调度。其中,事件调度是主线程。 件调度。其中,事件调度是主线程。
创建线程的方法: 创建线程的方法: 将需要独立运行的子任务代码放到从Thread类派生出 将需要独立运行的子任务代码放到从 类派生出 来的类的run方法中。 然后在主线程中原先调用该子 方法中。 来的类的 方法中 任务的地方先创建一个该线程类的实例, 任务的地方先创建一个该线程类的实例,再调用线程 中的start方法启动线程。新线程只能由 方法启动线程。 中的 方法启动线程 新线程只能由start方法启动 方法启动 然后才能执行run方法。 然后才能执行 方法。 方法
3、实现多个线程 、
例:多个记数程序。 多个记数程序。
4、线程的状态 、
5、Runnable接口 、 接口 前面介绍了如何通过创建自己的线程类来实现多 线程,即将线程类( 线程,即将线程类(Thread)与程序的主类 ) (Main)分离。 )分离。
class ห้องสมุดไป่ตู้ounterSubTask extends Thread { ... public void run( ) { ... } }
public class CounterMultiThread { public static void main(String [ ] args) { ... } }
如果CounterSubTask类,也就是run方法所在的 类 也就是 如果 方法所在的 类已经拥有另一个超类,那将无法继承 类已经拥有另一个超类,那将无法继承Thread类, 类 此时如何实现多线程呢?可以通过实现 此时如何实现多线程呢?可以通过实现Runnable 接口来实现多线程。 接口来实现多线程。 【例】 通过Runnable接口实现多个记数线程的Java 通过Runnable接口实现多个记数线程的Java Runnable接口实现多个记数线程的 小应用程序 。 程序代码见CounterThreadApplet .java 程序代码见 HTML文件见 文件见CounterThreadApplet.html 文件见 运行结果如下. 运行结果如下