进程与线程:深入理解进程和线程的关系到实际应用

1.什么是进程

​ 进程指的是计算机中运行的程序的实例。每个进程都是一个程序在执行过程中的一个独立单位,它拥有独立的内存空间和系统资源,可以被操作系统调度和管理。

​ 简单来说:正在运行的程序称之为进程。进程它是系统分配资源的基本单位。

2.什么是线程

​ 线程(Thread)是进程中的一个执行单元,是操作系统能够进行运算调度的最小单位。与进程不同的是,线程是在同一个进程中并发执行的多个执行流,它们共享同一进程的资源,包括内存空间、文件描述符和其他系统资源。

3. 进程和线程的关系

  1. 进程是系统资源(如内存、文件资源)的分配单位。每个进程拥有独立的内存空间和资源。
  2. 线程是 CPU 调度的基本单位,操作系统将 CPU 时间片分配给线程来执行指令。多个线程共享进程的地址空间和其他资源。
  3. 一个进程可以包含一个或多个线程,至少包含一个主线程(也称为主程序控制线程),这个线程负责执行程序的主要逻辑。

下面我们来举一个例子理解:

进程:

流水线工厂:整个工厂就是一个进程。它是一个独立的执行环境,有自己的内存空间、资源、和执行状态。

工作人员:在工厂里,每个工作人员都代表一个线程。工作人员可以同时处理不同的任务(例如装配、检验、包装),这些任务可以并行进行。

线程

任务:每一个具体的任务,比如装配部分、检验部分、包装部分等,可以看作是一个线程。多个任务(线程)可以同时在流水线上执行。

资源共享:在流水线中,工作人员可能需要共享某些资源(比如零件、设备),这就像线程可以共享进程的内存空间和资源一样。

进一步理解:

并行执行:在流水线上,不同的任务可以同时进行,就像多个线程可以同时在同一个进程中执行不同的操作。

资源隔离:虽然在流水线上,每个任务可能需要共享某些资源,但是每个任务有自己的工作区域(工作台),这就像线程可以共享进程的资源,但同时也有自己的栈空间和执行上下文。

整体效率:通过优化流水线上每个任务的工作效率(比如调整任务顺序、减少等待时间),可以提高整个工厂的生产效率;同样,通过合理使用多线程,可以提高进程的整体效率和响应速度。

4. 为什么使用多线程

充分利用了cpu,提高了程序的效率。

让cpu在等待时间执行其它的进程,就像流水线的工人在这条流水线的货物到来的间隔时间,完成其它流水线的任务一样,提高了cpu的利用率,增加了线程序的效率。

5. 创建线程的方式

在java中提供了三种创建线程的方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口

5.1 继承Thread类

可以创建一个类,继承自 Thread 类,并重写 run() 方法来定义线程的行为。

线程类:

// 继承Thread类
public class ThreadOne extends Thread{

    // 重写run方法,表示线程启动后执行的业务代码
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(this.getName()+"~~~"+i+"~~~");
        }
    }
}

测试类:

@Test
    public void threadTest01(){
        // 创建线程对象
        ThreadOne threadOne = new ThreadOne();
        // 开启线程,硬件底层调用线程的run方法
        threadOne.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("main~~"+i+"~~~");
        }
    }

运行结果:

在这里插入图片描述

可以看出,在运行期间会交叉打印,这就是cup在主线程执行的间隙的等待时间去执行了另一个线程

案例:四个窗口各卖一百张票

线程类:

public class ThreadFirst extends Thread {
    //四个窗口各卖100张门票
    private static int ticket = 100;
    @Override
    public void run() {
        while (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
            ticket--;
        }
        System.out.println(Thread.currentThread().getName()+"票卖完了");
    }
}

测试类:

@Test
    public void threadFirst() {
        ThreadFirst st1 = new ThreadFirst();
        ThreadFirst st2 = new ThreadFirst();
        ThreadFirst st3 = new ThreadFirst();
        ThreadFirst st4 = new ThreadFirst();
        st1.setName("窗口A");
        st2.setName("窗口B");
        st3.setName("窗口C");
        st4.setName("窗口D");
        st1.start();
        st2.start();
        st3.start();
        st4.start();
    }

运行结果:

在这里插入图片描述

5.2 实现Runnable接口

这种方法可以避免单继承的限制,因为Java中一个类只能继承一个父类,但可以实现多个接口。

线程类:

// 实现Runnable接口
public class ThreadTwo implements Runnable{
    // 实现run()方法
    @Override
    public void run() {
        //线程执行时的任务代码
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"~~~"+i+"~~~");
        }
    }
}

测试类:

@Test
    public void threadTest02(){
        //创建线程任务对象
        ThreadTwo threadTwo = new ThreadTwo();
        //创建线程对象
        Thread thread = new Thread(threadTwo);
        // 开启线程
        thread.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main~~"+i+"~~~");
        }
    }

运行结果:

在这里插入图片描述

案列:四个窗口共卖一百张票

线程类:

public class ThreadSecond implements Runnable{
    
    @Override
    public void run() {
        //四个窗口共卖100张票
        int ticket = 100;
        while (true) {
            if (ticket <= 0) {
                break;
            }
            //模拟延时
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "卖票,剩余" + ticket);
        }
    }
}

测试类:

 @Test
    public void threadSecond(){
        ThreadSecond threadSecond = new ThreadSecond();
        Thread thread1 = new Thread(threadSecond);
        Thread thread2 = new Thread(threadSecond);
        Thread thread3 = new Thread(threadSecond);
        Thread thread4 = new Thread(threadSecond);
        thread1.setName("窗口A");
        thread1.start();
        thread2.setName("窗口B");
        thread2.start();
        thread3.setName("窗口C");
        thread3.start();
        thread4.setName("窗口D");
        thread4.start();
    }

运行结果:

在这里插入图片描述

根据运行结果可以分析出会出现重卖的现象,还会出现超卖的现象,即剩余为负,我的电脑运行多次没出现超卖的结果,所以没有截图。

这是因为多个线程共享一个资源,导致了线程安全隐患问题。后期我们可以使用锁解决线程安全问题。本次先不涉及到此部分内容

5.3 实现Callable接口

Callable 接口类似于 Runnable 接口,但它允许线程执行有返回值的操作,并且可以在执行完毕后获取结果。

线程类:

// 实现Callable接口
public class ThreadThree implements Callable<Double> {
    // 实现call()方法
    @Override
    public Double call() throws Exception {
        // 求一千以内的3的倍数的和
        double sum = 0;
        for (int i = 0; i < 1000; i++) {
            if (i % 3 == 0){
                sum += i;
            }
        }
        return sum;
    }
}

测试类:

 @Test
    public void threadTest03() throws Exception{
        // 创建线程任务对象
        ThreadThree threadThree = new ThreadThree();
        // 封装到FutureTask
        FutureTask futureTask = new FutureTask<>(threadThree);
        // 传递futureTask,创建线程对象
        Thread thread = new Thread(futureTask);
        // 开启线程
        thread.start();
        // 获取执行结果
        Object o = futureTask.get();
        System.out.println(o);
    }

运行结果:

在这里插入图片描述

5.4 Thread类中常用的方法

start(): 启动线程并使其进入就绪状态。
run(): 线程运行时要执行的代码,通常不直接调用,而是通过start()间接调用。
sleep(long millis): 使线程休眠指定的毫秒数。
join(): 等待该线程终止。
interrupt(): 中断线程。
isAlive(): 判断线程是否处于活动状态。
setPriority(int newPriority): 设置线程的优先级。
getName()和setName(String name): 获取和设置线程的名称。

5.5 三种创建方法的区别

继承Thread类与实现Runnable接口比较:

继承 Thread 类的优缺点:

优点: 实现简单,可以直接调用 start() 方法启动线程。

缺点: 由于Java只支持单继承,如果已经继承了其他类,则无法再使用这种方式来实现线程。

实现 Runnable 接口的优缺点:

优点: 灵活性更高,可以避免单继承的限制,一个类可以同时实现多个接口。

缺点: 使用稍微复杂一些,需要创建一个 Thread 对象,并将 Runnable 对象传递给它。

实现Runnable接口与实现Callable接口比较:

  1. Runnable 接口的 run() 方法没有返回值,不能抛出异常,而 Callable 接口的 call() 方法可以返回一个结果,并且可以抛出受检异常。
  2. Runnable 接口可以直接作为 Thread 对象的构造参数,而Callable接口不能。
  3. Callable接口是对Runnable接口的补充。
  • 33
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值