当前位置: 首页 > news >正文

[JavaEE] 线程与进程的区别详解


 专栏简介: JavaEE从入门到进阶

题目来源: leetcode,牛客,剑指offer.

创作目标: 记录学习JavaEE学习历程

希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长.

学历代表过去,能力代表现在,学习能力代表未来! 


目录

认识线程(Thread)

1. 线程是什么?

2. 为什么要有线程?

3. 线程和进程的区别?

4. Java线程和操作系统线程的关系 

5. 创建多线程

6. 使用JConsole 查看线程状态


认识线程(Thread)

1. 线程是什么?

一个线程就是一个执行流 , 每个线程都可以按照自己的顺序来执行代码 , 多个线程同时执行着多份代码.

例如: 一家公司的会计张三去银行办理业务 , 业务范畴很广 , 有财务转账 , 社保缴纳 , 员工福利发放. 如果只有张三一个会计 , 就会耗费很长的时间. 为了节省时间 , 公司张三又叫来了李四和王五 , 三个人分别排队叫号 , 自此就有三个执行流共同完成任务 , 但本质上他们还是办理同一家公司的业务 . 此时我们就把这种情况称为多线程 , 将一个大任务分成多个小任务 , 交给不同执行流分别排队执行.其中李四和王五是张三叫来的 , 那么张三就是主线程.(Main Thread).


2. 为什么要有线程?

首先 , "并发编程" 成为 "刚需".

  • 单核CPU的发展遇到了瓶颈 , 想要提高算力 , 需要使用多核CPU. 而并发编程恰好能更充分的利用多核CPU资源.
  • 有些任务常见需要等待"IO" , 为了让程序在等待"IO"的同时做一些其他工作 , 也需要用到并发编程.

其次 , 虽然多进程能实现并发编程 , 但线程比进程更轻量.

  • 创建线程比进程更快
  • 调度线程比进程更快
  • 销毁线程比进程更快

 Tips:虽然线程比进程更轻量 , 但人们并不满足于此 , 于是有了"线程池"(Thread Pool)和协程(Coroutine)


3. 线程和进程的区别?

维度多进程多线程总结
数据共享 , 同步

数据是分开的 , 共享复杂;

同步简单.

多线程共享进程数据 , 共享简单;

同步复杂

各有优势
内存, CPU

占用内存多 , CPU利用率低

占用内存少 , CPU利用率高

线程占优
创建销毁, 切换创建销毁 , 切换复杂 , 速度慢创建销毁 , 切换简单 , 速度快线程占优
编程调试编程简单 , 调试简单编程复杂 , 调试复杂进程占优
可靠性进程间不会相互影响

一个线程挂掉将导致

整个进程挂掉

进程占优
分布式

适用于多核 , 多机分布;

如果一台机器不够 , 

扩展到多台机器比较简单

适用于多核分布线程占优
  • 进程包含线程 , 每个进程中至少有一个线程存在 , 即主线程.
  • 进程和进程之间不共享内存空间 , 同一个进程的多个线程之间共用进程的同一份资源.(内存和文件描述符表)
  • 进程是系统分配资源的最小单位 , 线程是系统调度的最小单位.

还是之前的例子 , 每个来银行办理业务的客户相当于一个进程 , 他们的票据肯定不同 , 否则银行卡中的钱就被别人取走了 , 而张三李四王五虽然是三个不同的执行流 , 但办理的都是同一家公司的业务 , 所以票据是共享的 , 这就是多线程和多进程最大的区别.


4. Java线程和操作系统线程的关系 

线程是操作系统中的概念 , 操作系统内核实现了线程这样的机制 , 并且提供了一系列的API供用户层使用 , 例如Linux系统的pthread库.

Java标准库中的Thread类可以看做是对操作系统提供的线程API做进一步的抽象和封装.


5. 创建多线程

1) 继承Thread重写run()

t.start 真正创建了一个线程 , 线程是独立的执行流. run() 只是描述了线程要执行的任务是什么 , 

class MyThread extends Thread{
    @Override
    public void run(){
            System.out.println("Hello thread");
    }
}
public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();//start 创建了一个新的线程 , 新的线程负责执行t.run().
        System.out.println("Hello main");
      
    }

2) 实现Runnable()

将任务与线程区分开来,让线程和任务之间解耦合.(低耦合) 好处是如果后期要改成多进程 , 或者线程池 , 或者协程.....此时代码改动比较小.

 class MyRunnable implements Runnable {
    //Runnable 作用 , 描述一个"要执行的任务" , run 方法就是任务执行的细节.
    @Override
    public void run() {
        System.out.println("Hello Thread");

    }
}
public static void main(String[] args) {
        //描述一个任务
        Runnable runnable = new MyRunnable();
        //把任务交给线程来执行
        Thread t = new Thread(runnable);
        t.start();
    }

3) 使用匿名内部类

new Thread 创建了 Thread 类的子类 , 因为子类没有名字叫匿名匿名内部类 , 并且让 t 引用指向该实例.

public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run(){
                System.out.println("Hello thread");
            }
        };
        t.start();
    }

4) 使用匿名内部类实现Runnable()

该方法与第二种方法本质相同. 只不过把实现 Runnable 的任务交给匿名内部类.最后将匿名内部类的实例交给 Thread 类的构造方法.

public static void main4(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello thread");
            }
        });
        t.start();
    }

5)j简便写法 Lambda表达式

直接把 lambda 传给Thread 构造方法.

 public static void main5(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("Hello world");
        });
        t.start();
    }

6. 使用JConsole 查看线程状态

JConsole 是 jdk 自带的一种基于JMX的可视化监控 , 管理工具.主要用于查看线程的状态.

打开 jdk 进入bin目录 , 找到 jconsole.

jconsole只能查看正在运行的线程状态 , 我们先在本地 ideal 运行一个多线程的Java程序.这时打开jconsole 找到我们创建的Java程序 , 点击连接.

 忽略不安全的连接提示 , 进入线程专栏.

 此时我们可以看到多个线程 , 其中main是主线程 , Thread-0是我们创建的另一个线程.其余线程都是JVM自带的.

 选择指定的线程后 , 在堆栈跟踪中就可以查看到线程调用栈具体的执行细节. 这对于后期多线程程序的调试工作有很大的用处.

相关文章:

  • pytorch:repeat()和expand()的区别
  • SpringBoot 整合 Shiro 实现动态权限加载更新+ Session 共享 + 单点登录
  • 国内内网穿透市场现状及头部厂商发展路线分析
  • JavaSE笔记——异常、断言
  • 通过静态LSP、LDP LSP、MPLS TE三种方式实现总部与分支的互通
  • python根据json数据画疫情分布地图
  • 一份不错的Java就业指导
  • 带你学懂数据结构中的八大排序(上)
  • IT30--IT与业务业务与ITIT价值(3年之约已满)
  • Docker的安装(Centos7)
  • 【动态规划篇】最少分割回文 编辑距离 不同的子序列
  • 嵌入式走过的路
  • 【面试高频题】难度 2/5,回溯算法经典运用
  • 程序员必备网站,建议收藏!
  • (四)汇编语言——简单程序
  • python3.6+scrapy+mysql 爬虫实战
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • fetch 从初识到应用
  • learning koa2.x
  • Mysql优化
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • Spark RDD学习: aggregate函数
  • TypeScript实现数据结构(一)栈,队列,链表
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 面试遇到的一些题
  • 使用 @font-face
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • #1015 : KMP算法
  • #android不同版本废弃api,新api。
  • #define,static,const,三种常量的区别
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • #mysql 8.0 踩坑日记
  • (LeetCode 49)Anagrams
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)大道至简,职场上做人做事做管理
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • ***检测工具之RKHunter AIDE
  • 、写入Shellcode到注册表上线
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .NET 表达式计算:Expression Evaluator
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • /etc/fstab和/etc/mtab的区别
  • @GetMapping和@RequestMapping的区别
  • @Not - Empty-Null-Blank
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [ C++ ] STL---仿函数与priority_queue