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 方法");
        }
    }
}
相关推荐
倒悬于世3 分钟前
JVM-类加载详情
java·开发语言·jvm
xiezhr5 分钟前
别再被VO、BO、PO、DTO、DO绕晕!今天用一段代码把它们讲透
java·后端·spring
zwhdlb17 分钟前
Java + 工业物联网 / 智慧楼宇 面试问答模板
java·物联网·面试
码熔burning33 分钟前
JVM 面试精选 20 题(续)
jvm·面试·职场和发展
刘一说34 分钟前
CentOS 系统 Java 开发测试环境搭建手册
java·linux·运维·服务器·centos
卷福同学40 分钟前
来上海三个月,我在马路边上遇到了阿里前同事...
java·后端
bingbingyihao3 小时前
多数据源 Demo
java·springboot
在努力的前端小白8 小时前
Spring Boot 敏感词过滤组件实现:基于DFA算法的高效敏感词检测与替换
java·数据库·spring boot·文本处理·敏感词过滤·dfa算法·组件开发
完全学不完8 小时前
JVM对象创建和内存分配
jvm