JavaEE 初阶篇-深入了解进程与线程(常见的面试题:进程与线程的区别)

🔥博客主页: 【小扳_-CSDN博客】**
❤感谢大家点赞👍收藏⭐评论✍**

文章目录

[1.0 进程概述](#1.0 进程概述)

[](#2.0 线程概述)[2.0 线程概述](#2.0 线程概述)

[2.1 多线程概述](#2.1 多线程概述)

[](#3.0 常见的面试题:谈谈进程与线程的区别)[3.0 常见的面试题:谈谈进程与线程的区别](#3.0 常见的面试题:谈谈进程与线程的区别)

[](#4.0 Java 实现多线程的常见方法)[4.0 Java 实现多线程的常见方法](#4.0 Java 实现多线程的常见方法)

[4.1 实现多线程方法 - 继承 Thread 类](#4.1 实现多线程方法 - 继承 Thread 类)

[4.2 实现多线程方法 - 实现 Runnable 接口](#4.2 实现多线程方法 - 实现 Runnable 接口)


1.0 进程概述

一个程序运行起来,就会对应一个进程,进程是系统分配资源的基本单位。每个进程都有自己的地址空间、代码、数据、堆栈等资源,可以独立运行并与其他进程隔离。

进程特点:

1)进程是程序的执行实例,是计算机系统中最基本的执行单位。

2)每个进程有自己的地址空间、资源和状态,相互独立运行,互不干扰。

进程的状态:

1)就绪态(Ready):进程已经准备好运行,等待系统分配处理器资源。

2)运行态(Running):进程正在执行指令,占用处理器资源。

3)阻塞态(Blocked):进程因等待某些事件发生而暂时停止运行。

4)终止态(Terminated):进程执行完毕或被终止,释放资源。

2.0 线程概述

是进程中的实际执行单元。线程是系统调度执行的基本单位。一个进程可以包含一个或多个线程,共享进程的资源,但每个线程有自己的栈空间和执行路径。

线程特点:

1)线程是进程中的执行单元,可以看作是轻量级的进程。

2)同一进程中的线程共享进程的地址空间和资源,可以直接访问进程的全局变量和数据。线程共享进程的资源,减少资源的重复占用,提高资源的利用效率。

3)线程之间的切换比进程之间的切换更快速,因为线程共享相同的地址空间。

线程的状态:

1)就绪态(Ready):进程已经准备好运行,等待系统分配处理器资源。

2)运行态(Running):进程正在执行指令,占用处理器资源。

3)阻塞态(Blocked):进程因等待某些事件发生而暂时停止运行。

4)终止态(Terminated):进程执行完毕或被终止,释放资源。

2.1 多线程概述

多线程是指在一个程序中同时执行多个线程,每个线程可以独立执行不同的任务或操作。在Java中,多线程可以让程序更高效地利用计算机的多核处理器,提高程序的性能和响应速度。

3.0 常见的面试题:谈谈进程与线程的区别

1)资源占用方面上的区别:

进程拥有独立的地址空间和资源,进程与进程之间相互独立,即使一个进程出现了某些因素的影响,不能运行了,另一个进程也不会受到影响。

线程共享所属进程的地址和资源,包括全局变量、栈空间等,线程之间可以直接通信。若在一个进程中有若个线程中,即使只有一个线程出现问题,那么所有的线程都有可能会收到影响。

2)通信和同步方面上:

进程通信比较复杂,需要使用 IPC 机制,如管道、消息队列、共享内存等。

线程之间共享进程的资源,可以直接访问全局变量,线程通信更加方便。

3)切换开销方面上的区别:

进程切换的开销比较大,需要保存和恢复整个进程的状态,包括内存映像、寄存器等。

线程切换的开销比较小,因为线程共享进程的资源,只需要保存和回复线程的稀有数据。

举个例子:

线程与进程的区别:

4.0 Java 实现多线程的常见方法

1)继承 Thread 类。2)实现 Runnable 接口。

4.1 实现多线程方法 - 继承 Thread 类

先创建一个类继承 Thread 类,重写 run 方法。还需要在主函数中利用 start 方法启动。这样就创建了一个线程,调用 start 方法之后,系统会自动调用重写的 run 方法,也就是回调函数。交给系统执行 run 方法。

在 mian 中也是一个线程,称为主线程,主线程是自动创建的,而 thread 线程则是我们手动创建出来的。

代码如下:

java 复制代码
public class demo1 {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();

        while (true){
            System.out.println("正在执行主线程");
        }

    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        while (true){
            System.out.println("正在执行 run 线程");
        }
    }
}

运行结果:

以上代码和运行结果都是多线程所展示的,接下来对比一下单线程代码和运行结果:

java 复制代码
public class demo1 {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.run();

        while (true){
            System.out.println("正在执行主线程");
        }

    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        while (true){
            System.out.println("正在执行 run 线程");
        }
    }
}

注意观察,这里没有用到 start 方法,那么就意味着没有创建新的线程当前是主线程。因为没有创建新的线程,所以就不会有系统自动调用重写的 run 方法,那么我们自己手动调用 run 方法也是可以的,不过还是在同一个线程里面,并没有创建新的线程。因此,这里只能输出 "正在执行 run 线程" 这条语句,只能等到这循环结束后,才会执行下一个循环,因为在同一个线程里面,不能多并行。

运行结果:

除了以上方法可以看出来是否是多线程代码,还可以用到 jconsole.exe 这个应用程序,直观的感受出来。还是用到以上的多线程代码,来观察:

进入的页面找到相应的 .java 文件:

进入后,可以看到一个 java 应用程序运行的时候,至少有 15 个线程:

可以我们手动创建的线程 Thread-0 还有自动创建的主线程:

剩下的线程都是 jvm 帮我们做的一些其他工作,涉及到的负责垃圾回收的,负责记录调试信息的......

详细补充:

1)start 方法调用操作系统提供的"创建线程"的 API ,在内核中创建对应 PCB ,并且把 PCB 加入到链表中。run 方法则是在进一步的系统调度到这个线程了之后,系统自动就会执行上诉 run 方法中的逻辑。

2)多线程的调度顺序是无序的,在操作系统内部也称为"抢占式执行"。任何一个线程,在执行到任何一个代码的过程中,都可以被其他线程抢占掉它的 cpu 资源,于是 cup 就给别的线程执行了。这样的抢占式执行,充满了随机性,正是这样的随机性,使多线程的程序,执行效果,也会难以预测,甚至可以会引入 bug 。

除了以上的写法之外,还有用匿名内部类形式。

代码如下:

java 复制代码
public class demo2 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("正在运行 run 方法");
                }
            }
        };
        thread.start();

        while (true){
            System.out.println("正在运行 main 方法");
        }
    }
}

还可以用 lambda 方式进行进一步的简化:

java 复制代码
public class demo2 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true){
                System.out.println("正在运行 run 方法");
            }
        });
        thread.start();

        while (true){
            System.out.println("正在运行 main 方法");
        }
    }
}

4.2 实现多线程方法 - 实现 Runnable 接口

为了提高代码的灵活性,可以将线程的任务与线程本身分离,使代码结构更清晰。

先实现 Runnable 接口,一样的需要重写 run 方法,再把这个实例作为参数传入到创建 Thread 类中。最后调用 start 方法启动线程。

代码如下:

java 复制代码
public class demo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();

        while (true){
            System.out.println("正在运行 main 方法");
        }
    }

}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("正在运行 run 方法");
        }
    }
}

同样也可以用匿名类内部类方式:

java 复制代码
public class demo4 {
    public static void main(String[] args) {
        Thread thread = new Thread(()-> {
                while(true) {
                    System.out.println("正在运行 run 方法");
                }
        });

        thread.start();

        while (true){
            System.out.println("正在运行 main 方法");
        }
    }
}
相关推荐
考试宝2 分钟前
国家宠物美容师职业技能等级评价(高级)理论考试题
经验分享·笔记·职场和发展·学习方法·业界资讯·宠物
测开小菜鸟5 分钟前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
caridle1 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋31 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花2 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端2 小时前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan2 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava