什么是线程?线程和进程的关系?如何创建/查看线程?

这篇具有很好参考价值的文章主要介绍了什么是线程?线程和进程的关系?如何创建/查看线程?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一. 认识线程(Thread)

1.1 概念

1.1.1 什么是线程

进程进一步细化为线程, 是程序内部的一条执行路径. 一个进程中至少有一个线程. 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间"同时"执行多份代码.

1.1.2 线程存在的意义

① “并发编程"成为"刚需”

  • 单核 CPU 的发展遇到了瓶颈. 要想提高算力, 就需要多核 CPU. 而并发编程能更充分利用多核 CPU 资源.
  • 有些人物场景需要"等待IO", 为了让等待IO的时间能去做一些其他的工作, 也需要用到并发编程.

② 虽然多进程也能实现并发编程, 但是线程比进程跟轻量.

  • 创建和销毁的速度更快
  • 调度的速度更快

③ 线程虽然比进程轻量, 但是人们还不满足, 于是又有了"线程池(ThreadPool)" 和 “协程(Coroutine)”.

1.1.3 进程和线程之间的区别和联系

  • 进程包含线程, 都是实现并发编程的方式. 每个进程至少有一个线程, 即主线程.
  • 进程和进程之间不共享内存空间,可以保持系统的稳定性; 同一个进程的线程之间共享同一个内存空间(操作系统的线程), 一旦一个线程出现异常, 可能会导致整个进程异常, 容易出现线程安全问题.
  • 一个PCB描述一个线程, 多个PCB描述一个进程. 一个进程中的所有PCB内的内存指针和文件描述符表是一样的, 但是上下文, 状态, 优先级等属性是不一样的. 这也说明了, 同一个进程中的线程共用同一份资源(内存 + 硬盘), 但是每个线程独立去CPU上调度.
  • 进程是操作系统进行资源分配的基本单位, 而线程是操作系统进行调度执行的基本单位. 创建进程的时候已经分配了资源, 后续创建进程, 直接共用之间的资源即可.

1.1.4 Java的线程和操作系统的线程

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

Java中的线程是对系统级别的线程的封装和抽象.

操作系统级别下, 同一个进程的线程之间共享同一个内存空间;

而Java中的线程有私有空间.

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

1.2 创建线程

① 继承Thread类

  1. 创建一个线程类, 继承自Thread类

  2. 重写run方法: 线程入口方法, 描述线程执行的动作.

    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("这里是线程运行的代码");
       }
    }
    
  3. 创建MyThread类的实例

    MyThread t = new MyThread();
    
  4. 调用 start 方法启动线程

    t.start(); // 线程开始运行
    
    • 这个操作就会在底层调用操作系统提供"创建线程"的API, 同时就会在操作系统内核里面创建出对应的pcb结构, 并且加入到对应的链表中.
    • 此时, 这个新创建出来的线程就会参与到CPU的调度中, 这个线程接下来要执行的工作, 就是刚刚上面重写的run方法.

代码解析:

class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("MyThread");
        }
   }
}
public class Main {
    MyThread t = new MyThread();
    t.start();
    while (true) {
            System.out.println("Main");
    }
}

第十行t.start()创建出了新的线程, 执行run()中的代码.

原来的主线程继续往下执行

主线程和新线程是并发执行的关系, 根据操作系统的调度执行.

注意:

  • 如果自己手动调用run()方法, 那么就只是普通方法, 没有启动多线程模式.
  • run()方法由JVM调用, 什么时候调用, 执行的时候都由操作系统的CPU调度决定.
  • 想要启动多线程, 必须调用start方法
  • 一个线程对象只能调用一次start()方法启动, 如果重复调用了, 则将抛出以上的异常"IllegalThreadStateException"

② 实现Runnable 接口

  1. 实现Runnable接口

    class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("这里是线程运行的代码");
       }
    }
    
  2. 创建Thread类的实例, 调用Thread的构造方法将Runnable对象作为参数

    Thread t = new Thread(new MyRunnable());
    
  3. 调用start方法

    t.start();
    

通过实现Runnable接口, 使得该类有了多线程的特征. 所有的分线程要执行的代码都在run方法里面.

在启动多线程的时候, 需要先通过Thread类的构造方法Thread(Runnable target)构造出对象, 然后调用Thread对象的start方法来运行多线程代码.

实际上, 所有的多线程代码都是通过运行Thread.start()来运行的, 因此, 不管是继承Thread类还是实现Runnable接口来实现多线程, 最终还是通过Thread的对象的API来控制流程的.

说明: Runnable对象仅仅作为Thread对象的target, Runnable实现类里包含的run()方法仅作为线程执行体. 而实际的线程对象依然是Thread实例, 只是该Thread线程负责执行其target的run()方法.

这一方法, 将线程要执行的任务和线程本身, 进一步解耦合了.

对比两种方法

联系:

Thread类实际上也是实现了Runnable接口的类

public class Thread extends Object implements Runnable

区别:

  • 继承Thread: 线程存放Thread子类run方法中.
  • 实现Runnable: 现成代码存放在接口的子类的run方法.

实现Runnable接口比继承Thread类所具有的优势

  • 避免了单继承的局限性
  • 多个线程可以共享同一个接口实现类的对象, 非常适合多个相同线程来处理同一份资源
  • 增加程序的健壮性, 实现解耦操作, 代码可以被多个线程共享, 代码和线程独立.

③ 变形写法

  1. 匿名内部类创建Thread子类的对象.

    public class Demo3{
        Thread t1 = new Thread() {
            @Override
            public void run() {
                System.out.println("使用匿名类创建 Thread 子类对象");
            }
        };
        t1.start();
    }
    

    说明:

    new Thread(): 创建一个子类, 继承自Thread, 这个子类是匿名的, 并且是在Demo3这个类的内部创建的.

    ② 在子类中重写了run方法

    ③ 创建了该子类的实例, 并且使用t1这个引用来指向.

  2. 匿名内部类创建Runnable子类的对象

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("使用匿名类创建 Runnable 子类对象");
        }
    });
    

    说明:

    new Runnable(): 创建一个类, 实现Runnable接口.

    ② 在类中重写了run方法

    ③ 创建了该类的实例, 并把这个实例作为参数传给了Thread的构造方法.

  3. lambda表达式创建Runnable子类对象

    Thread t3 = new Thread(() -> System.out.println("使用匿名类创建 Thread 子类对象"));
    Thread t4 = new Thread(() -> {
        System.out.println("使用匿名类创建 Thread 子类对象");
    });
    

    ④ 其他写法

④ 其他写法

  • 基于Callable

    Callable<Integer> callable = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            //
            return null;
        }
    };
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
    Thread thread = new Thread(futureTask);
    thread.start();
    Integer result = futureTask.get();
    
  • 基于线程池

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(4);
        service.submit(new Runnable() {
            @Override
            public void run() {
                //
            }
        });
    }
    

    ExecutorService: 线程池对象

    Executors.newFixedThreadPool(int nThreads): 创建固定线程数量的线程池

    • Executors: 工厂类
    • newFixedThreadPool(int nThreads): 工厂类方法 创建固定线程数量的线程池
    • newCachedThreadPool(): 创建线程数量动态变化的线程池
    • newSingleThreadExecutor(): 创建单个线程的线程池
    • newScheduledThreadPool(int corePoolSize): 周期性线程池, 类似于定时器的效果
    • 上面四个方法都是对类ThreadPoolExecutor的封装, ThreadPoolExecutor 提供了更多的可选参数, 可以进一步细化线程池行为的设定.

    service.submit(Runnable task): 向线程池中添加任务.

1.3 查看线程

找到当前项目使用的jdk的位置, 并双击打开

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

双击bin目录, 找到jconsole.exe

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

双击jconsole.exe, 会出现以下窗口

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

选择本地进程, 并找到当前运行的线程名称, 再点击连接

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

若出现以下窗口, 选择不安全连接.

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

出现以下窗口后, 点击线程

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

左下角就列出了所有的线程, 不仅有主线程和自己创建的线程, 还有JVM自带的线程.

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言

点击某个线程, 就能得到该线程的具体信息

什么是线程?线程和进程的关系?如何创建/查看线程?,Javaee,java,开发语言文章来源地址https://www.toymoban.com/news/detail-616967.html

到了这里,关于什么是线程?线程和进程的关系?如何创建/查看线程?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 中的线程是什么,如何创建和管理线程-上(十一)

    Java 中的线程是指程序中可以独立执行的最小单位。在 Java 中,创建线程通常有两种方式:继承 Thread 类和实现 Runnable 接口。线程的管理包括控制线程状态、线程优先级、线程同步等。 一、Java 中的线程 线程是程序中能够独立执行的最小单位,它具有自己的执行路径、调用栈

    2024年02月03日
    浏览(39)
  • JavaSE、JavaEE和JavaME与Java的关系是什么?

    JavaSE、JavaEE和JavaME都是建立在Java语言基础之上的不同分支,它们共同构成了Java平台的不同方面和应用领域。 1.JavaSE(Java Platform, Standard Edition)是Java平台的基础,它提供了Java语言的核心库和基本功能,用于开发各种类型的应用程序。JavaSE包含了Java的基本类库、语言特性以及J

    2024年02月15日
    浏览(53)
  • 【Java基础教程】(四十二)多线程篇 · 上:多进程与多线程、并发与并行的关系,多线程的实现方式、线程流转状态、常用操作方法解析~

    理解进程与线程的区别; 掌握Java 中多线程的两种实现方式及区别; 掌握线程的基本操作方法; 进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程 。多进程操作系统能同时运行多

    2024年02月16日
    浏览(48)
  • Java进程线程介绍创建和执行销毁并理解线程安全和线程池 Native Method

    进程和线程都是一个控制流程。 一个进程通常对应于一个程序。 一个程序可以由多个不同的线程构成。 一个进程就是一个应用程序 一个应用程序面对多个用户则多个进程 一个进程则多个线程 多个线程共享资源且携带数据操作 多进程资源隔离 多线程的核心在于多个代码块

    2024年02月02日
    浏览(46)
  • JavaEE 初阶篇-深入了解进程与线程(常见的面试题:进程与线程的区别)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 进程概述         2.0 线程概述         2.1 多线程概述         3.0 常见的面试题:谈谈进程与线程的区别         4.0 Java 实现多线程的常见方法         4.1 实现多线程方法 - 继承

    2024年04月13日
    浏览(48)
  • 多线程的优点是什么?如何创建和启动一个线程?线程的状态有哪些?什么是线程安全?

    多线程的优点包括: 提高程序的执行效率:多线程可以同时执行多个任务,充分利用CPU资源,提高程序的整体执行效率。 提高系统的响应速度:多线程可以将耗时的任务放在后台执行,使得用户界面保持流畅,提高系统的响应速度。 提高系统的可靠性:多线程可以将任务分

    2024年02月15日
    浏览(62)
  • 进程线程的关系

    举个例子   滑稽老师吃100只鸡 如何加快滑稽老师吃鸡的效率?? 有一个方案,搞两个房间,两个滑稽老师  一个滑稽吃50只鸡,速度一定会大幅度增加 多进程的方案  创建新的进程  就需要申请更多的资源(房间和桌子) 另一个方案, 使用多线程 房间和桌子还是那些,但

    2024年04月14日
    浏览(34)
  • 【JavaEE】_线程与多线程的创建

    目录 1. 线程的概念 2. 创建与使用多线程 2.1 方式1:继承Thread类 2.2 方式2: 实现Runnable接口 2.3 以上两种创建线程方式的对比 3. 多线程的优势-增加运行速度 进程的存在是由于系统的 多任务执行需求 ,这也要求程序员进行并发编程; 使用多进程是完全可以实现并发编程的,

    2024年02月19日
    浏览(34)
  • 【JavaEE初阶】线程的概念与创建

    本节目标 认识多线程 创建多线程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 一个线程就是一个 “执行流” . 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之

    2024年02月07日
    浏览(38)
  • Java中String类型的创建关系、什么是常量池、以及StringBuilder/Buffer等

    这段 Java 代码中,字符串 s1 和 s2 都使用字面量的方式赋值,它们在编译时会被放入常量池中。由于字符串常量池的特性,s1 和 s2 在常量池中的引用地址是相同的,因此 s1 == s2 的结果为 true。 而字符串 s3 和 s4 是通过 new 创建的,它们在内存中是两个不同的对象,因此

    2023年04月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包