目录
2、进程与进程之间不能共享内存空间,而线程之间可以共享内存资源
进程是操作系统对一个正在运行的程序的一种抽象,可以把进程看作程序的一次运行,是操作系统进行资源分配的基本单位
是一个用于描述进程的结构体,一个进程可以有一个PCB也可以有多个
1.pid:进程的身份标识,同一个主机同一时刻进程的pid是唯一的
2.内存指针:用于描述进程持有的内存资源,一个可执行程序运行后,操作系统会把核心资源加载到内存里
3.文件描述符表:用于描述一个进程持有的文件资源,用于记录进程打开的文件
4.进程状态:用于描述一个进程能不能被调度到CPU执行,有两种状态,一种是就绪状态,可以被调度到CPU执行,还有一种是堵塞状态,不可以被调度到CPU执行
5.进程优先级:描述进程执行的优先关系
6.进程上下文:一个进程在CPU执行了一会后,切换到别的进程,就需要保存存档,下次执行该进程时,就恢复原来继续往下执行
7.进程记账信息:记录一个进程执行的时间
每个PCB是通过双向链表来组织的
给每个进程分配的内存资源,叫虚拟地址空间,不是真实的物理地址,通过专门的设备MMU来检测进程是否访问越界,后访问物理地址,使用虚拟地址空间相当于增加了进程之间的隔离性,一个进程不能访问另一个进程的内存空间
有了虚拟地址空间增加了隔离性但也有了新的问题---进程之间的交互,进程之间的交互就设计到进程间的通信,进程之间的通信,是通过一个多个进程都能访问到的公共资源比如,一块内存,一个网卡等
创建PCB-》分配资源-》插入链表
从链表删除 -》释放持有的资源-》销毁PCB
一个线程就是一个人执行流,每个线程都可以按照顺序执行自己的代码,多个线程同时执行多个代码
并发编程的刚需,当需要多个进程时,进程的创建与销毁操作效率比较低,而多个线程创建与销毁,相比比较高效
每一个线程都是一个执行流,都可以在CPU进行调度,如果把进程比作工厂,线程就相当于是工厂里的流水线
创建第一个线程时系统分配资源,后续创建线程不需要申请资源,线程销毁时也只是销毁到最后一个线程才释放资源,一个PCB 也就是一个线程
在一定程度上线程使用,是高效的,而并不是越多越好,CPU的核心数是有限的,如果线程的数量超出一定范围反而会降低效率
在操作系统里面原生的线程API是C语言的,在Java里将其封装为Java风格的API
让一个类继承Thread然后重写run方法
run方法里面就是这个线程要做的事,run方法就是线程的入口方法
- class MyThread extends Thread{
- @Override
- public void run() {
- while(true){
- System.out.println("这个线程要执行的逻辑");
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- }
- }
- public class demo1 {
-
- public static void main(String[] args) {
- MyThread myThread = new MyThread();
- myThread.start();
- }
- }
使用这个类实例化一个对象并不是创建了线程,而通过对象调用了父类里的start方法才是创建了一个线程,main方法执行的逻辑是主线程,main就是主线程的入库口方法,线程是并发执行的,也就是run里面的代码与main函数里面的代码是同时执行的
实现接口后重写run方法,实例一个该类的对象,然后实例化一个Thread的对象,在构造函数传入实例化的实现Runnable接口的类的对象,通过Thread对象调用start方法就创建了一个线程,这种创建方法将创建线程与线程所执行的逻辑分开,实现了代码的解耦合
- class MyRunnable implements Runnable{
- @Override
- public void run() {
- System.out.println("这是这个线程要执行的逻辑");
- }
- }
-
- public class demo2 {
- public static void main(String[] args) {
- MyRunnable myRunnable = new MyRunnable();
- Thread thread = new Thread(myRunnable);
-
- thread.start();
- }
- }
- public class demo3 {
- public static void main(String[] args) {
- Thread thread = new Thread(){
- @Override
- public void run() {
- System.out.println("线程执行的逻辑");
- }
- };
-
- thread.start();
- }
- }
- public class demo4 {
- public static void main(String[] args) {
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.println("线程执行的逻辑");
- }
- });
- }
- }
- public class demo4 {
- public static void main(String[] args) {
- Thread thread = new Thread(()->{
- System.out.println("线程执行的逻辑");
- });
- }
- }
让a自增到一个值重复两次自增,通过执行时间来判断两种方式的效率
- public class demo4 {
- public static final long NUM = 10_0000_0000L;
- public static void main(String[] args) {
- func1();
- func2();
- }
-
- //串行代码
- public static void func1(){
- long begin = System.currentTimeMillis();
-
- long a = 0L;
- for (int i = 0; i < NUM; i++) {
- a++;
- }
-
- a = 0;
- for (int i = 0; i < NUM; i++) {
- a++;
- }
-
-
- long end = System.currentTimeMillis();
-
- System.out.println("串行代码执行时间"+(end-begin)+"ms");
- }
-
- //线程代码
- public static void func2(){
- long begin = System.currentTimeMillis();
-
- Thread thread1 = new Thread(()->{
- long a = 0L;
- for (int i = 0; i < NUM; i++) {
- a++;
- }
- });
-
- Thread thread2 = new Thread(()->{
- long a = 0L;
- for (int i = 0; i < NUM; i++) {
- a++;
- }
- });
-
- thread1.start();
- thread2.start();
-
- //让线程执行完毕
- try {
- thread1.join();
- thread2.join();
-
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- long end = System.currentTimeMillis();
- System.out.println("线程代码执行时间"+(end-begin)+"ms");
- }
- }