这是我对进程、线程的了解,有不足之处希望大家多多指点,我们一起学习、进步#^_^#。
一、进程:
进程是程序的一次执行,就是在操作系统中运行的程序;
进程是不能执行任务的;
进程在运行时创建的资源随着进程的终止而死亡。
二、线程:
1、线程是用来执行任务的,线程彻底执行完任务A才会去执行任务B;
2、进程本身是不能执行任务的,进程想要执行任务必须的有线程,线程是进程内部的一个独立的执行单元,同时只能执行一个任务。线程被分为两种。主线程(用户界面线程)和子线程(工作线程或后台线程);
3、线程执行完毕就会被销毁。
4、线程有分为主线程和子线程
①主线程(又叫父线程):当应用程序启动时自动创建和启动,通常用来处理用户的输入并响应各种事件和信息。
需要注意的是,主线程的终止也就意味着该程序的结束。
②子线程:顾名思义,子线程有主线程来创建,用来帮助主线程执行程序的后台处理任务。
若子线程A创建子线程B,那么在创建之后子线程A和子线程B是相互独立的,多个线程之间在效果上可以同时执行。
一个进程中可以有多个线程,并且所有线程都在该进程的虚拟地址空间中,可以使用进程的全局变量和系统资源
5、线程的状态
线程从创建、运行到结束总是处于这五种状态之一:新建状态、就绪状态、运行状态、阻塞状态、死亡状态。
①新建状态:
当用操作符new创建一个线程时,线程还没有开始运行,那么线程处于新建状态,此时程序还没有开始运行线程中的代码
②就绪状态:
一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
③运行状态
当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。
④阻塞状态
线程运行过程中,可能由于各种原因进入阻塞状态:
1)线程通过调用sleep方法进入睡眠状态;
2)线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
3)线程试图得到一个锁,而该锁正被其他线程持有;
4)线程在等待某个触发条件;
......
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
⑤ 死亡状态 有两个原因会导致线程死亡:
1)run方法正常退出而自然死亡,
2)一个未捕获的异常终止了run方法而使线程猝死。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false。
三、多线程:
为了同时执行多个线程,就产生了多线程。
①目前大多数的APP都需要链接服务器,而访问服务器的速度可能快,也可能很慢。如果一个APP访问服务器的操作没有在子线程操作的话,在该APP访问服务器的过程中,该软件是不能响应用户的操作的,只有该APP访问结束以后APP才能响应用户的操作,这就造成线程阻塞,也就是我们常见的卡顿现象。一条线程在同一时间内只能执行一个任务,一个进程可以有多个线程来执行不同的任务,从而提高程序的执行效率,避免线程阻塞。
②操作系统会根据线程的优先级(线程的优先级可以手动设置)来安排CPU的时间,优先级高的线程,优先调用的几率会更大,同级的话,看线程执行的先后。
③同一时间内,CPU只能处理一条线程,只有一条线程在工作。多线程并行执行,其实就是各个线程不断切换,因为执行切换的时间很快很快,就造成了同时执行的假象,原理如下,比如A,B两个线程:
1)A执行到某一时间段要切换了,可A任务没完成,系统就会把A当前执行的位置和数据以入栈的方式保存起来
2)然后B线程执行,B执行时间到了,它的位置状态等也会被系统保存到B的栈中。
3)系统自动找到A的栈,将A之前保存的数据恢复,又可以从A之前断开的状态继续执行下去,如此循环。
④系统每开一个线程都有比较大的开销。若线程开的过多,不仅会占用大量内存和让程序变得更加复杂,而且会加重CPU的负担,这样的软件,会使你的手机在冬天变成暖手宝。
四、益处:
1、使用多线程可以提高程序的执行效率,避免线程阻塞造成的卡顿现象。
2、可以提高资源利用率
注意:一个进程中可以有多个线程,但不能滥用线程,因为:
1、开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB,可以自己设置内存大小,但必须是4的倍数),如果开启大量的线程,会占用大量的内存空间,降低程序的性能
2、线程越多,CPU在调度线程上的开销就越大
3、滥用线程会使程序设计更加复杂:比如线程之间的通信、多线程的数据共享
线程例子:
//
// MoreImageViewController.m
// 多线程
//
// Created by 王维 on 16/3/2.
// Copyright © 2016年 王维. All rights reserved.
//
#import "MoreImageViewController.h"
#define kUrl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"
@interface MoreImageViewController()
{
int imageIndex;
UIImage *image;
NSMutableArray *threadArray;//用来存放子线程的数组
}
@end
@implementation MoreImageViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
self.edgesForExtendedLayout = UIRectEdgeNone;
imageIndex = 100;
threadArray = [NSMutableArray array];
// 1、创建多个UIImageView
for (int row = 0; row < 3;row++) {
for (intlist = 0; list < 2;list++) {
UIImageView *imageView= [[UIImageView alloc]initWithFrame:CGRectMake(10+list*200, 10+row*200, 200, 200)];
imageView.backgroundColor= [UIColor greenColor];
imageView.tag = imageIndex++;
[self.view addSubview:imageView];
}
}
// 2、 创建多个子线程
for (int index= 0; index < 6;index++) {
// object:@(index):object传的参数是index是为了区别子线程
NSThread *thread = [[NSThread alloc]initWithTarget:selfselector:@selector(thread:)object:@(index)];
[thread start];
[threadArray addObject:thread];
}
}
//int类型的数据用@()包起来就转换成nsnumber类型。创建线程中的withObject:@(index)表明需要一个NSNumber类型来接受
//通过URL加载图片
- (void)thread:(NSNumber*)sender{
// 3、加载图片
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:kUrl]]];
// 通过线程休眠实现顺序加载
[NSThread sleepForTimeInterval:[sender intValue]];
// 在这里加上一个判断,获取当前线程的状态,如果是休眠状态,就让它退出
NSThread *thread = [NSThreadcurrentThread];
if (thread.isCancelled== YES) {
[NSThread exit];
}
// 4、回到主线程
[self performSelectorOnMainThread:@selector(updateUI:) withObject:sender waitUntilDone:YES];
}
//5、更新UI
- (void)updateUI:(NSNumber*)sender{
// ①先找到某个线程对应的imageView
UIImageView *imageView = [self.view viewWithTag:[senderintValue]+100];
imageView.image = image;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[NSThread currentThread];
NSLog(@"%@",threadArray);
for (int index= 0; index < 6;index++) {
NSThread *thread = threadArray[index];
if (thread.isFinished== NO) {
// 点击屏幕,取消未完成的线程
[thread cancel];
}
}
}
@end