这里不管进程与线程的概念,先看看进程与线程的使用。
现有代码如下,内含加法和减法函数,程序运行时按顺序调用加法和减法函数。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private int mInt1 = 10;
private int mInt2 = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"add result " + add(mInt1,mInt2));
Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
}
private int add(int int1,int int2){
for (int i = 0 ; i < 500 ; i ++){
Log.d(TAG, "inner add " + i);
}
return (int1 + int2);
}
private int subtract(int int1,int int2){
for (int i = 0 ; i < 500 ; i ++){
Log.d(TAG, "inner subtract " + i);
}
return (int1 - int2);
}
}
运行程序(即打开app)后如下所示。
2020-08-17 16:16:50.620 11449-11449/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 5
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 6
2020-08-17 16:16:50.621 11449-11449/com.example.myapplication D/MainActivity: inner add 7
............................
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 2
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 3
2020-08-17 16:16:50.635 11449-11449/com.example.myapplication D/MainActivity: inner subtract 4
............................
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 494
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 495
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:16:50.651 11449-11449/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:16:50.652 11449-11449/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:16:50.652 11449-11449/com.example.myapplication D/MainActivity: subtract result 5
运行时间从16:16:50.620
到16:16:50.652
,所需时间为0.032s。
现将程序简单修改,引入线程。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private int mInt1 = 10;
private int mInt2 = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"add result " + add(mInt1,mInt2));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
}
}).start();
}
private int add(int int1,int int2){
for (int i = 0 ; i < 500 ; i ++){
Log.d(TAG, "inner add " + i);
}
return (int1 + int2);
}
private int subtract(int int1,int int2){
for (int i = 0 ; i < 500 ; i ++){
Log.d(TAG, "inner subtract " + i);
}
return (int1 - int2);
}
}
最后log如下所示(不同设备可能运行结果略微不一样,但是总归是轮流调用add和subtract函数)。
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:21:28.546 11828-11848/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:21:28.546 11828-11848/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:21:28.546 11828-11847/com.example.myapplication D/MainActivity: inner add 5
...................................................
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: inner add 498
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: inner add 499
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:21:28.559 11828-11847/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:21:28.559 11828-11848/com.example.myapplication D/MainActivity: subtract result 5
运行时间从16:21:28.546到16:21:28.559,所需时间为0.013s。
由此可以看出,在输出同样的日志的情况下,引入线程后,耗时减少了。
而所谓进程,是程序的一次执行,这里可以理解为app的一次打开,即一次执行。
进程通常由程序、数据和进程控制块(Process Control Block,PCB)组成。
1.进程控制块。进程控制块是进程存在的唯一标志。
这里我只看看进程标识符。
进程标识符就是PID,每个应用在打开后,系统会给app分配一个标识符。
cmd进入控制台。
adb shell
ps
image.png
显示当前所有进程,打开app后,输入ps |grep + 包名。
ps |grep com.example
u0_a119 29441 759 1678764 45676 SyS_epoll_ 0000000000 S com.example.myapplication
出处:Android 查看进程ID(PID)比较进程优先级
各列参数意义:
USER 进程当前用户;
PID Process ID,进程ID;
PPID Process Parent ID,进程的父进程ID;
VSIZE Virtual Size,进程的虚拟内存大小;
RSS Resident Set Size,实际驻留”在内存中”的内存大小;
WCHAN 休眠进程在内核中的地址;
PC Program Counter;
NAME 进程名;
2.程序。
程序部分描述了进程需要完成的功能。我这里的demo就是加减数据的功能。
3.数据。
数据部分包括程序执行时所需的数据及工作区。
这里涉及到程序执行时数据的存储。
一个可执行文件运行起来的话它就变成了进程,然后系统会给进程分配一个4G大小的虚拟地址空间。其中前3G内存是用户空间,最后1G是内核空间。所有的进程有各自的用户空间,但所有的进程都共享一个内核空间。
线程:
出处:《软件设计师教程》
传统的进程有两个基本属性: 可拥有资源的独立单位;可独立调度和分配的基本单位。由于在进程的创建、撤销和切换中, 系统必须为之付出较大的时空开销, 因此在系统中设置的进程数目不宜过多, 进程切换的频率不宜太高, 这就限制了并发程度的提高。引入线程后, 将传统进程的两个基本属性分开,线程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过创建线程来完成任务, 以减少程序并发执行时付出的时空开销。
进程与线程的定义为:
线程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过创建线程来完成任务, 以减少程序并发执行时付出的时空开销。
现在来看并发与并行。
并发(concurrency)和并行(parallelism)的区别
并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。
并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
将代码稍微修改,执行减法之前先休眠。
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"add result " + add(mInt1,mInt2));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.currentThread().sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
}
}).start();
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 0
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 1
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 2
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 3
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 4
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 5
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 6
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 7
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 8
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 9
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 10
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 11
2020-08-17 16:41:31.668 14006-14032/com.example.myapplication D/MainActivity: inner add 12
................................
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 49
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 0
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 50
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 1
2020-08-17 16:41:31.669 14006-14032/com.example.myapplication D/MainActivity: inner add 51
2020-08-17 16:41:31.669 14006-14033/com.example.myapplication D/MainActivity: inner subtract 2
................................
2020-08-17 16:41:31.682 14006-14032/com.example.myapplication D/MainActivity: inner add 499
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 436
2020-08-17 16:41:31.682 14006-14032/com.example.myapplication D/MainActivity: add result 15
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 437
2020-08-17 16:41:31.682 14006-14033/com.example.myapplication D/MainActivity: inner subtract 438
................................
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 496
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 497
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 498
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: inner subtract 499
2020-08-17 16:41:31.684 14006-14033/com.example.myapplication D/MainActivity: subtract result 5
由于执行加法和减法函数的开始时间不同,16:41:31.668
开始打印加法函数中的log,16:41:31.669
开始打印减法函数中的log,并且,到16:41:31.669
时加函数并未完成,因此此时程序是并发执行
,而不是并行执行。
时间轴如下所示。
如果没有使用延时的情况下,也就是代码如下的情况下。
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"add result " + add(mInt1,mInt2));
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG,"subtract result " + subtract(mInt1,mInt2));
}
}).start();
}
时间轴如下所示。
image.png
log打印开始时间是同一时间,并且同时打印log,因此是程序是并行执行
,并且也是并发执行
。
参考链接:
并发(concurrency)和并行(parallelism)的区别
《软件设计师教程》
Android 查看进程ID(PID)比较进程优先级
网友评论