[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.

[JavaEE] 线程与进程的区别详解_第1张图片

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

[JavaEE] 线程与进程的区别详解_第2张图片

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

[JavaEE] 线程与进程的区别详解_第3张图片

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

[JavaEE] 线程与进程的区别详解_第4张图片

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

[JavaEE] 线程与进程的区别详解_第5张图片

你可能感兴趣的:(JavaEE,java,开发语言,多线程)