深入浅出Java的多线程编程——第一篇

news2024/11/23 16:45:29

目录

1. 认识线程(Thread)

1.1 概念

1.1.1 线程是什么

1.1.2 为啥需要线程

1.1.3 进程和线程的区别

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

1.2 第一个多线程程序

1.3 创建线程的方式(5种)

1.3.1 继承Thread类

1.3.2 实现Runnable接口

1.3.3 继承Thread类,使用匿名内部类

1.3.4 实现Runnable接口,使用匿名内部类

1.3.5 使用lambda表达式创建线程(推荐)

1.4 多线程的优势—增加运行速度

2. Thread类及常见方法

2.1 Thread的常见构造方法

2.2 Thread的几个常见属性


前情回顾:操作系统、进程和线程_木子斤欠木同的博客-CSDN博客

1. 认识线程(Thread)

1.1 概念

1.1.1 线程是什么

一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码 . 多个线程之间 " 同时 " 执行着多份代码.
举个栗子:
我们设想如下场景:
       一家公司要去银行办理业务,既要进行财务转账,又要进行福利发放,还得进行缴社保。
       如果只有张三一个会计就会忙不过来,耗费的时间特别长。为了让业务更快的办理好,张三又找 来两位同事李四、王五一起来帮助他,三个人分别负责一个事情,分别申请一个号码进行排队, 自此就有了三个执行流共同完成任务,但本质上他们都是为了办理一家公司的业务。
       此时,我们就把这种情况称为多线程,将一个大任务分解成不同小任务,交给不同执行流就分别 排队执行。其中李四、王五都是张三叫来的,所以张三一般被称为主线程(Main Thread)。 

1.1.2 为啥需要线程

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

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

  • 创建线程比创建进程更快.
  • 销毁线程比销毁进程更快.
  • 调度线程比调度进程更快.
最后, 线程虽然比进程轻量, 但是人们还不满足, 于是又有了 "线程池"(ThreadPool) 和 "协程"
(Coroutine)

1.1.3 进程和线程的区别

  • 进程是包含线程的. 每个进程至少有一个线程存在,即主线程。
  • 进程和进程之间不共享内存空间. 同一个进程的线程之间共享同一个内存空间.

多进程就是例如同时打开QQ音乐和微信,他们连各自为一个进程。
多线程就是例如打开微信的聊天功能和朋友圈,他们各自为一个线程。
进程是资源分配的基本单位!
线程共享同一份资源!
  • 进程是系统分配资源的最小单位,线程是系统调度的最小单位。

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

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

Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装

注:也就是说Java的线程和操作系统的线程是两回事,能思想线程的功能是操作系统内核
 

1.2 第一个多线程程序

感受多线程程序和普通程序的区别:

  • 每个线程都是一个独立的执行流
  • 多个线程之间是 "并发" 执行的
class MyThread extends Thread{
    @Override
    public void run(){
        while(true){
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        myThread.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

使用jconsole命令观察线程

这是jdk提供的工具,能够让我们查看java进程里面线程的详情!

jconsole只能分析java进程,不能识别非java写的进程~~

除了main和Thread-0两个线程之外,剩下都是JVM自己创建的!

1.3 创建线程的方式(5种)

1.3.1 继承Thread类

class MyThread extends Thread{
    @Override
    public void run(){
        while(true){
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        myThread.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

1.3.2 实现Runnable接口

public static void main(String[] args) {
        Runnable run = new Thread2();
        Thread thread = new Thread(run);
        thread.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


public class Thread2 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("hello run");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

注:以上两种创建线程的区别在于,实现Runnable接口的方法使线程和线程要做的事情分开了,达到了解耦合的作用

1.3.3 继承Thread类,使用匿名内部类

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

    }

1.3.4 实现Runnable接口,使用匿名内部类

    public static void main(String[] args) {
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });
    }

1.3.5 使用lambda表达式创建线程(推荐)

    public static void main(String[] args) {
        Thread t3 = new Thread(() -> 
            System.out.println("hello")
        );
    }

1.4 多线程的优势—增加运行速度

可以观察多线程在一些场合是可以提高程序整体运行的效率

  • 使用 System.currentTimeMillis()可以记录当前系统的 纳秒 级时间戳.

(1)串行

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for(int a = 0;a < 1000;a++){
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        for(int b = 0;b < 1000;b++){
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

(2)并发

    public static void main(String[] args) {
        Thread t = new Thread(()->{
            for(int a = 0;a < 1000;a++){
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        long start = System.currentTimeMillis();
        t.start();
        for(int b = 0;b < 1000;b++){
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

 

2. Thread类及常见方法

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。

用我们上面的例子来看,每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象,就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

2.1 Thread的常见构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建下线程对象,并命名
Thread(Runnable target,String name)使用Runnable对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组,这个目前我们了解即可

2.2 Thread的几个常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台进程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况,下面我们会进一步说明
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,即简单的理解,为 run 方法是否运行结束了
  • 线程的中断问题,下面我们进一步说明
     

特别说明:isDaemon()方法

true表示是后台线程

false表示是前台进程

(1)后台进程不阻止Java进程结束。哪怕后台线程还没有执行完,Java进程该结束就结束了。

(2)前台线程会阻止Java进程结束,必须得java进程中所有的前台线程都执行完,Java进程才会结束。

(3)创建的线程默认都是前台的,可以通过setDaemon()方法设置为后台。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1041626.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑开机慢问题的简单处理

电脑用久了&#xff0c;开机时间要10-20分钟特别慢&#xff0c;一下介绍两种简单有效处理方式&#xff0c;这两种方式经测试不会影响原系统软件的使用&#xff1a; 方式一&#xff1a;禁用非必要启动项【效果不是很明显】 利用360里面的优化加速禁用启动项【禁用启动项还有其…

红色模板和黑色模板的区别

红色建筑模板和黑色建筑模板是常见的建筑支模材料&#xff0c;它们在颜色、材料、性能和适用范围等方面存在显著的区别。下面将详细介绍这两种建筑模板的区别。 首先&#xff0c;红色建筑模板通常由胶合板或其他木材制成&#xff0c;外观呈红色&#xff0c;而黑色建筑模板则采用…

MySQL数据库入门到精通6--进阶篇(锁)

5. 锁 5.1 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决…

沐风老师3DMAX刀剑轨迹拖尾插件SwordTrails使用方法详解

3DMAX刀剑轨迹拖尾插件SwordTrails使用教程 SwordTrail刀剑轨迹拖尾插件&#xff0c;是一款简单的运动轨迹特效工具。 【适用版本】 3dmax2011-2023&#xff08;不仅于此范围&#xff09; 【安装方法】 该插件无需安装&#xff0c;使用时直接拖动插件脚本文件到3dmax视口中打…

联机手写汉字识别系统技术要求与测试规程

声明 本文是学习GB-T 18790-2010 联机手写汉字识别系统技术要求与测试规程. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了联机手写汉字识别系统的技术要求和测试规程。 本标准适用于微型计算机、手持式信息处理设备等数字化设…

功能定义-后方碰撞预警

功能概述 后方碰撞预警(Rear Collision Warning)&#xff0c;简称RCW&#xff0c;其功能表现为实时监测车辆后方环境&#xff0c;并在可能受到后方碰撞危险时发出警告信息 报警区域 其中&#xff1a; L&#xff1a;表示后方盲区&#xff0c;受布置及传感器FOV影响 W&#xff1…

Java实现byte数组与Hex互转

十六进制字符的输出大写字符&#xff1a;0123456789ABCDEF 十六进制字符的输出小写字符&#xff1a;0123456789abcdef下面使用十六进制大写字符。 1、方式1 public class HexStringUtils {private static final char[] HEX_CHAR_TABLE {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B,…

00-MySQL数据库的使用-上

一 数据库基础知识 先谈发音 MySQL如何发音&#xff1f;在国内MySQL发音有很多种&#xff0c;Oracle官方文档说 他们念作 My sequal[si:kwəl]。 数据库基本概念 数据 数据&#xff08;Data&#xff09;是指对客观事物进行描述并可以鉴别的符号&#xff0c;这 些符号是可识别…

一篇文章全面解析Modbus协议中的消息帧

在 Modbus网络通信的两种传输模式中&#xff08; ASCII或RTU&#xff09;&#xff0c;传输设备以将Modbus消息转为有起点和终点的帧&#xff0c;这就允许接收的设备在消息起始处开始工作&#xff0c;读地址分配信息&#xff0c;判断哪一个设备被选中&#xff08;广播方式则传给…

MySQL 基础

本系列文章为【狂神说 Java 】视频的课堂笔记&#xff0c;若有需要可配套视频学习。 1. 简介 数据库&#xff08;DB&#xff0c;Database&#xff09;是安装在操作系统上的存储数据的软件。 关系型数据库&#xff08;RDB&#xff09;以行列形式存储数据。 非关系型数据库&am…

如何访问TDH中Inceptor 底层的元数据库TxSQL

如何访问TDH中Inceptor 底层的元数据库TxSQL 1 Inceptor概述 在大数据生态系统中&#xff0c;HIVE是离线数据仓库事实上的标准&#xff0c;绝大多数的大数据分析型系统或数据仓库系统&#xff0c;都是基于HIVE来构建的。 在星环的大数据平台TDH中&#xff0c;在功能上对应开…

PWN环境搭建

虚拟机Ubuntu安装 工具&#xff1a;Vmware 16 以及 Ubuntu 18或20 来源&#xff1a;清华大学开源软件镜像站 | Tsinghua Open Source Mirror 虚拟机安装流程 安装很简单&#xff0c;按照提示一步步来即可 处理器可以多给一些&#xff0c;我给了8个&#xff0c;内核数量不…

CCS介绍

CCS介绍 设置主体颜色 修改字体的颜色和大小 安装一些插件 CCS中的App中心 切换工作空间 导入工程

CarbonData详细解析

一、CarbonData简介 CarbonData是一种新型的Apache Hadoop本地文件格式&#xff0c;使用先进的列式存储、索引、压缩和编码技术&#xff0c;以提高计算效率&#xff0c;有助于加速超过PB数量级的数据查询&#xff0c;可用于更快的交互查询。同时&#xff0c;CarbonData也是一种…

AnyDesk多ID集中控制台V2.0

网盘下载 AnyDesk多ID集中控制台V2.0 软件介绍&#xff1a; 首先大家要知道AnyDesk软件是干嘛的&#xff1f;国外的远程协助工具&#xff0c;和TeamViewer同一个软件&#xff0c;TeamViewer确定需要登录&#xff0c;使用限制5分钟等等缺点&#xff0c;所以自己就用易语言开发An…

uni-app:实现页面效果1

效果 代码 <template><view><view class"add"><image :src"add_icon" mode""></image></view><view class"container_position"><view class"container_info"><view c…

69.渲染函数如何提高Vue应用程序的效率

通过使用虚拟 DOM&#xff0c;Vue 可以比直接操作真实 DOM 更高效地更新和渲染用户界面。渲染函数可用于在服务器上预渲染组件&#xff0c;从而提高应用程序的初始加载性能。渲染函数可让我们完全控制组件的结构和内容&#xff0c;从而构建自定义的复杂用户界面。 h() 函数&…

Java笔记:手写spring之aop

手写spring之aop 仓库地址: Raray-chuan/mini-spring 博文列表: 导读手写spring之ioc手写spring之aop手写spring之简单实现springboot 1.什么是AOP AOP(Aspect-oriented Programming), AOP翻译过来叫面向切面编程, 核心就是这个切面. 切面表示从业务逻辑中分离出来的横切…

【排序算法】冒泡排序、插入排序、归并排序、希尔排序、选择排序、堆排序、快速排序

目录 几大排序汇总 1.冒泡排序 性能: 思路和代码: 2.插入排序 性能: 思路和代码: 3.归并排序 性能: 思路和代码: 4.希尔排序 性能: 思路和代码: 5.选择排序 性能: 思路和代码: 6.堆排序 性能: 思路和代码: topK问题 7.快速排序 性能: 思路和代码: 几大排…

vue3自定义全局Loading

自定义插件之全局Loading ElementPlus的默认全局Loading 如果完整引入了 Element Plus&#xff0c;那么 app.config.globalProperties 上会有一个全局方法$loading&#xff0c;同样会返回一个 Loading 实例。 名称说明类型默认targetLoading 需要覆盖的 DOM 节点。 可传入一…