首页 > 系统相关 >深入理解线程与进程:从基础概念到实际应用

深入理解线程与进程:从基础概念到实际应用

时间:2024-07-04 15:58:04浏览次数:19  
标签:Thread start 深入 new 进程 线程 public

1. 什么是线程和进程?

  • 进程:进程是操作系统分配资源和调度的基本单位,它是一个正在运行的程序,每个进程都有独立的内存空间和系统资源。一个程序可以同时启动多个进程。
  • 线程:线程是进程中的一个执行单元,负责执行程序的代码。一个进程可以包含多个线程,这些线程共享进程的内存空间和资源,但每个线程有自己的栈和寄存器。

让我们用一个现实生活中的例子来解释进程和线程。

1.1 进程和线程的通俗解释

  • 进程:可以把进程想象成一家餐厅。在这家餐厅中,餐厅本身就是一个进程,它有自己的厨房、餐厅、工作人员和顾客。每个餐厅(进程)都是独立的,有自己的空间和资源。
  • 线程:在这家餐厅中,每个厨师就是一个线程。多个厨师(线程)在同一个厨房(进程)里工作,共享厨房的资源,比如灶台、锅、食材等。每个厨师有自己的任务和工作区域,但他们都在为餐厅(进程)服务。

1.2 具体例子

  • 餐厅(进程):假设有两家餐厅A和B,每家餐厅都有自己的厨房、菜单和顾客。餐厅A的厨师和餐厅B的厨师不会共享资源,他们各自独立运行,就像两个独立的进程。

  • 厨师(线程):在餐厅A里,有多个厨师同时在厨房工作。他们可以同时准备不同的菜肴(执行不同的任务),但他们共享厨房的所有资源(内存、灶台等)。即使他们同时工作,他们的工作还是在同一个餐厅(进程)里进行的。

1.3 关键点

  • 进程:是独立运行的实体,有自己的内存空间和系统资源。餐厅A和餐厅B彼此独立。
  • 线程:是进程中的执行单元,多个线程共享进程的资源。餐厅A里的多个厨师共享同一个厨房。

1.4 进一步理解

  • 餐厅扩展:如果餐厅(进程)需要扩展,比如增加新的菜品或提高服务速度,可以增加更多的厨师(线程)来同时准备更多的菜品,提高效率。
  • 线程的好处:使用线程可以让餐厅(进程)更高效,因为多个厨师(线程)可以同时工作,提高了资源的利用率和任务的执行速度。
  • 线程的问题:多个厨师(线程)在同一个厨房(进程)里工作时,可能会出现争抢资源的情况,比如争用灶台或食材,需要协调和管理,避免冲突。

2. 创建线程的方式

2.1 继承Thread类

通过创建一个继承自Thread类的子类,然后重写run方法。

class MyThread extends Thread {
    public void run() {
        System.out.println("Thread is running");
    }
}

//在main方法中创建线程,调用start方法开启线程
MyThread t = new MyThread();
t.start();

案例

四个窗口各卖100张门票。

① 线程类
public class SellTicketThread extends Thread{
    //四个窗口各卖100张门票
    private static int ticket = 100;
    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + ticket + "张票");
                ticket--;
            } else {
                System.out.println(Thread.currentThread().getName()+"票卖完了");
                break;
            }
        }
    }
}
② 测试类
public class Test {
    public static void main(String[] args) {
        SellTicketThread st1 = new SellTicketThread();
        SellTicketThread st2 = new SellTicketThread();
        SellTicketThread st3 = new SellTicketThread();
        SellTicketThread st4 = new SellTicketThread();
        st1.setName("窗口A");
        st2.setName("窗口B");
        st3.setName("窗口C");
        st4.setName("窗口D");
        st1.start();
        st2.start();
        st3.start();
        st4.start();
    }
}
③ 运行结果

在这里插入图片描述

2.2 实现Runable接口

通过实现Runnable接口的类,并将该类的实例作为参数传递给Thread对象完成线程的创建。

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Thread is running");
    }
}
//将该线程类的实例作为参数传递给`Thread`对象完成线程的创建
Thread t = new Thread(new MyRunnable());
t.start();

案例

四个窗口共卖100张票

根据运行结果可以分析出问题:超卖和重卖现象。

这是因为多个线程共享一个资源,导致了线程安全隐患问题。后期解决线程安全问题。 后期我们可以使用锁解决。

① 线程类
public class SellTicketRunnable 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);
        }
    }
}
② 测试类
public class Test {
    public static void main(String[] args) {
        SellTicketRunnable sellTicketRunnable = new SellTicketRunnable();
        Thread thread1 = new Thread(sellTicketRunnable);
        Thread thread2 = new Thread(sellTicketRunnable);
        Thread thread3 = new Thread(sellTicketRunnable);
        Thread thread4 = new Thread(sellTicketRunnable);
        thread1.setName("窗口A");
        thread1.start();
        thread2.setName("窗口B");
        thread2.start();
        thread3.setName("窗口C");
        thread3.start();
        thread4.setName("窗口D");
        thread4.start();
    }
}
③ 运行结果

在这里插入图片描述

2.3 实现Callable接口并使用FutureTask

实现Callable接口并通过FutureTask包装,最后传递给Thread对象。

class MyCallable implements Callable<String> {
    public String call() {
        return "Callable result";
    }
}

//将该类的线程的实例对象包装到FutureTask类中,然后传递给Thread,完成线程的创建
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread t = new Thread(futureTask);
t.start();

案例

求1-1000内3的倍数的整数和。

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        //求1-1000以内3的倍数的整数和
        int sum = 0;
        for (int i = 1; i <= 1000; i++) {
            if (i % 3 == 0) {
                sum += i;
            }
        }
        return sum;
    }
}
public class TestCallable {
    public static void main(String[] args) throws Exception{
        //创建本线程类
        MyCallable mc = new MyCallable();
        //封装到FutureTask
        FutureTask ft = new FutureTask<>(mc);
        //传递给thread
        Thread thread = new Thread(ft);
        //开启线程
        thread.start();
        //获取执行结果
        Object o = ft.get();
        System.out.println(o);
    }
}

3. Thread类中常用的方法

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

4. Runnable和Callable的区别

4.1 接口

  • Runnable:是一个函数式接口,只包含一个run()方法,不返回任何结果,也不抛出检查型异常。
  • Callable:也是一个函数式接口,包含一个call()方法,可以返回结果并且可以抛出检查型异常。

4.2 方法签名

  • Runnablerun()方法没有返回值。
  • Callablecall()方法返回一个泛型类型的结果。

4.3 使用场景

  • Runnable适用于不需要返回结果或不抛出检查型异常的任务。
  • Callable适用于需要返回结果或可能抛出检查型异常的任务。

标签:Thread,start,深入,new,进程,线程,public
From: https://blog.csdn.net/qq_51774011/article/details/140171539

相关文章

  • java使用Netty实现TCP收发消息的例子,多线程并且含断线自动重连
    需求:有一个TCP的服务,需要使用Netty开发一个TCP连接并收发消息的程序。要求多线程并且含断线自动重连能力。组织结构,使用JavaMaven编程方式功能还包含读取配置文件和log4j2写日志部分 完整代码:App.javapackagecom.LSpbxServer;importorg.slf4j.Logger;import......
  • linux进程被杀掉日志,Linux进程突然被杀掉(OOM killer),查看系统日志
    Linux进程被杀掉(OOMkiller),查看系统日志基本概念:Linux内核有个机制叫OOMkiller(OutOfMemorykiller),该机制会监控那些占用内存过大,尤其是瞬间占用内存很快的进程,然后防止内存耗尽而自动把该进程杀掉。内核检测到系统内存不足、挑选并杀掉某个进程的过程可以参考内核源代码......
  • 进程D 状态的产生及原因解释
    在Linux系统中,进程的D状态表示进程处于不可中断的睡眠状态(UninterruptibleSleep)。这种状态通常由进程等待某些资源或事件引起,这些资源或事件无法立即可用。以下是一些常见的导致进程进入D状态的原因:I/O操作:等待磁盘I/O完成:进程可能正在等待磁盘读取或写入操作......
  • 多线程编程的基本概念,C++标准库中的多线程支持(std::thread,std::async),如何处理线程同步
    多线程编程在现代计算机系统中非常重要,因为它能够使程序同时执行多个操作,提高计算效率。以下是多线程编程的基本概念及如何在C++标准库中使用std::thread和std::async进行多线程编程,同时处理线程同步和并发问题。多线程编程的基本概念线程(Thread):线程是一个轻量级的进程,是......
  • 线程的基本使用
    线程1.什么是线程线程(Thread)是计算机科学中的基本概念,用于描述一个程序内部的执行路径。一个线程可以被看作是一个程序内部的独立执行流,能够单独执行代码,并与其他线程共享同一进程的资源。以下是关于线程的一些详细信息:线程的特点:轻量级:线程是比进程更小的执行单位。一个进......
  • 用PyQt5打造炫酷界面:深入解析pyqt5-custom-widgets
    在PyQt5中,使用自定义小部件可以为应用程序增添更多实用性和时尚感。pyqt5-custom-widgets是一个开源项目,提供了一系列有用且时尚的自定义小部件,如开关按钮、动画按钮等。本文将详细介绍pyqt5-custom-widgets的安装和使用方法。安装可以使用PIP进行安装(根据你的平台,可能是......
  • JAVA多线程快速入门
    什么是多线程概述线程线程是操作系统能够进行运算调度的最小单位它被包含在进程之中,是进程中的实际运作单位简单理解应用软件中互相独立,可以同时运行的功能进程进程是程序的基本执行实体/系统分配资源的基本单位作用充分利用cpu提......
  • 字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
    在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。字......
  • Java多线程编程
    1.进程进程是指操作系统中正在运行的程序实例,它是系统资源分配的基本单位。每个进程都拥有独立的内存空间和系统资源,可以看作是程序的一次执行过程。2.线程线程是进程中的执行单元,也被称为轻量级进程(LightWeightProcess)。一个进程可以包含多个线程,这些线程共享进......
  • Linux进程间的通信方式(二)System V 共享内存
    文章目录前言1.共享内存的概念1.1什么是共享内存1.2linux的内存管理机制1.3内存映射2.共享内存的接口分类3.共享内存的相关操作函数3.1ftok函数(获取一个key值)3.2shmget函数(创建或获取一个共享内存描述符)3.3shmat函数(映射共享内存地址空间)3.4shmdt函数(......