(Java高级教程)第一章Java多线程基础-第一节1:多线程概念和Java中创建线程的方式

2023/11/30 5:36:48

文章目录

  • 一:什么是线程和多线程
  • 二:Java多线程引入
  • 三:Java线程生命周期
  • 四:创建线程的方法
    • (1)通过继承Thread类
    • (2)通过实现Runnable接口
    • (3)变种形式
      • ①:使用匿名内部类创建Thread子类对象
      • ②:使用匿名内部类实现Runnable接口
      • ③:使用lambda表达式
  • 五:多线程的优势

一:什么是线程和多线程

线程:关于进程和线程的概念这里就不再重复了,具体可见

  • (王道408考研操作系统)第二章进程管理-第一节5:线程的概念
  • (王道408考研操作系统)第二章进程管理-第一节6:线程的实现方式和多线程模型

要想进行下一步学习,你至少要清楚以下概念

  • 明白计算机的基本工作流程(冯诺依曼,寄存器、指令等概念)

  • 什么是进程,如何理解进程

  • 并行和并发

  • 进程PCB的概念

  • 进程调度与通信的概念

  • 什么是线程、为什么要引入线程

  • 进程和线程的区别

  • 线程调度

  • 用户级线程和内核级线程

  • 多线程的概念

二:Java多线程引入

  • 注意:不管是C++、Python还是Java,在多线程这一部分总是不太容易讲解,所以这里我们通过一个简单的例子来帮助大家理解

在之前的学习中,我们的代码只是运行在一个执行流中,如何证明?你会发现在这种单执行流中,不可能存在两个循环语句同时运行

  • 当你运行Java程序后,就会产生一个进程,此时main方法是该进程中唯一存在的一个线程,也即主线程,当有多个线程时mian方法就是所有线程的入口方法
  • 下面代码中Thread.sleep()用于将线程阻塞一定时间
public class Test {
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println("main线程运行中");
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

而在多线程中,由于线程之间是并发运行的,所以每个线程内部都可以独立的进行工作,所以对于整个进程或程序来说,它就可以同时运行多个循环语句

在Java中,会使用Thread类管理线程,用户在使用时线程时,需要自己实现一个线程类然后继承该Thread类,接着在内部重写run方法,run方法里面的逻辑,就是这个线程要执行的工作,如下

  • 注意:这仅是一种常见的创建线程的方式,还有其它方法,稍后说明
class MyThread extends Thread{
    @Override
    public void run(){
        while(true) {
            System.out.println("这是MyThread线程");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

创建线程时,直接实例化线程类即可,不过需要注意只有在调用start方法时,该线程才算被真正创建出来。如下,我们在main方法中实例化刚才的线程,然后在main方法内也写上一个循环语句

package threading;

class MyThread extends Thread{
    @Override
    public void run(){
        while(true) {
            System.out.println("这是MyThread线程");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class TestDemo {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        while(true) {
            System.out.println("这是main线程");
            Thread.sleep(1000);
        }
    }
}

运行程序,你会发现两个循环在“交替”运行,这说明现在两个线程正在并发执行

请添加图片描述

多线程编程相较于普通编程难度会大大提高,稍有不慎就可能会导致整个系统崩溃。类似于任务管理器,为了方便我们对线程信息的掌控,Java提供了jconsole命令来观察线程

找到jdk安装目录,在bin文件下找到jconsole.exe,启动上面的程序后,双击jconsole.exe

在这里插入图片描述
在打开的窗口中选中对应的程序,然后点击连接

在这里插入图片描述

选择不安全的连接在这里插入图片描述

进入监视窗口,选择线程

在这里插入图片描述
如下为线程运行信息,其中mainThread-0就是上面例子所展示的那两个线程。可以发现还有很多其他线程,它们各司其职,有负责垃圾回收的,有负责监视的,也有负责跟踪的等等

在这里插入图片描述

三:Java线程生命周期

Java线程生命周期:在Java中,一个线程会历经如下状态,分别有与之对应的操作或条件

  • 新建状态:使用关键字newThread类或其子类建立一个线程对象后,该线程就处于新建状态。它会保持这个状态直到程序start()这个线程
  • 就绪状态:当线程对象调用了start()方法后,该线程进入就绪状态。就绪状态的线程处于就绪队列中,等待JVM调度
  • 运行状态:如果就绪状态线程获取CPU资源,就可以执行run(),此线程便处于运行状态。处于运行状态的线程可以重新变为阻塞、就绪或死亡状态
  • 阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)的等方法,失去所占用的资源后,就会进入阻塞状态。在睡眠时间已到或重新获得资源后可再次进入就绪状态。分为等待阻塞、同步阻塞或其他阻塞
  • 死亡状态:个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态

在这里插入图片描述

四:创建线程的方法

(1)通过继承Thread类

通过继承Thread类:格式如下,这种方法使线程和线程需要完成的任务绑定在了一起,直接使用this就表示当前线程对象的引用。所以这种写法耦合性太强,未来改动时代价较大

1:继承Thread类创建一个线程类
class MyThread extends Thread{
	@override
	public void run(){
		System.out.println("线程运行逻辑")
	}
}

2:创建MyThread类实例
MyThread thread0 = new MyThread();

3:调用start方法启动线程
thread0.strat();

(2)通过实现Runnable接口

通过实现Runnable接口:格式如下,这种方法把线程和线程需要完成的任务分开了,使用Runnable专门表示线程需要完成的任务,此时this表示的是Runnbale对象的引用,如果要引用线程时则要借助Thread.currentThread()。所以这种写法耦合性较低,未来改动时代价较低

1:实现Runnable接口
class MyRunnable implements Runnable{
    @Override
    public void run(){
        System.out.println("线程运行逻辑");
    }
}

2:创建Thread类实例,在调用Thread构造方法时将Runnable对象作为target参数
Thread thread0 = new Thread(new MyRunnable());

3:调用start方法
thread0.start();

例子

package threading;

class MyRunnable implements Runnable{
    @Override
    public void run(){
        while(true) {
            System.out.println("这是MyRunnable线程");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class TestDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread0 = new Thread(new MyRunnable());
        thread0.start();
        while(true) {
            System.out.println("这是main线程");
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

(3)变种形式

①:使用匿名内部类创建Thread子类对象

package threading;

public class TestDemo3 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            //匿名内部类
            public void run(){
                while(true) {
                    System.out.println("这是MyThread线程");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        thread.start();

        while(true) {
            System.out.println("这是main线程");
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

②:使用匿名内部类实现Runnable接口

package threading;

public class TestDemo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(
                //匿名内部类
                new Runnable() {
                    @Override
                    public void run() {
                        while(true) {
                            System.out.println("这是MyRunnable线程");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
        );
        thread.start();

        while(true) {
            System.out.println("这是main线程");
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

③:使用lambda表达式

package threading;

public class TestDemo5 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread0 = new Thread(
                () -> {
                    while(true) {
                        System.out.println("lambda表达式Thread");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
        );
        thread0.start();

        while(true) {
            System.out.println("这是main线程");
            Thread.sleep(1000);
        }
    }
}

在这里插入图片描述

五:多线程的优势

多线程的最大优势还是在于提高计算速度,如下分别使用串行和并发的方式完成同样的运算

package threading;

public class threadAdvantaged {
    //数字300亿
    public static final long COUNT = 200_0000_0000L;


    public static void main(String[] args) {
        serial_execution();

        concurrency_execution();
    }

    //串行执行
    public static void serial_execution(){
        long begin = System.currentTimeMillis();

        long a = 0;
        for (long i = 0; i < COUNT; i++){
            a++;
        }

        a = 0;
        for (long i = 0; i < COUNT; i++){
            a++;
        }

        long end = System.currentTimeMillis();
        System.out.println("串行执行用时:" + (end - begin) + "ms");
    }

    //并发执行
    public static void concurrency_execution(){
        long begin = System.currentTimeMillis();

        Thread thread1 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        long a = 0;
                        for (long i = 0; i < COUNT; i++){
                            a++;
                        }
                    }
                }
        );
        Thread thread2 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        long a = 0;
                        for (long i = 0; i < COUNT; i++){
                            a++;
                        }
                    }
                }
        );

        thread1.start();
        thread2.start();

        //阻塞
        try{
            thread1.join();
            thread2.join();
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("并发执行用时:" + (end - begin) + "ms");

    }
}

在这里插入图片描述


http://www.jnnr.cn/a/110355.html

相关文章

【机器学习大杀器】Stacking堆叠模型-English

1. Introduction The stacking model is very common in Kaglle competitions. Why? 【机器学习大杀器】Stacking堆叠模型&#xff08;English&#xff09; 1. Introduction 2. Model 3: Stacking model 2.1 description of the algorithms: 2.2 interpretation of the es…

有了PySnooper,不用print、不用debug轻松查找问题所在!

PySnooper是一个非常方便的调试器&#xff0c;它是通过python注解的方式来对函数的执行过程进行监督的。 应用起来比较简单&#xff0c;不用一步一步的去走debug来查找问题所在&#xff0c;并且将运行过程中函数的变量值打印出来结果一目了然&#xff0c;相当于替代了print函数…

张益唐与黎曼猜想

一个人活在世界上&#xff0c;可以有不同层次的贡献&#xff0c;有正的有负的。唐山烧烤店打人的那种人&#xff0c;就是典型的负的贡献。正的贡献有大有小&#xff0c;像我这样开发一个小软件&#xff0c;写一段小博文&#xff0c;这是小的贡献&#xff1b;像张益唐这样&#…

【SQL小题】- (一)基础查询篇

&#x1f308;刷题&#xff0c;面试&#xff0c;求职&#xff0c;快来牛客网一起成为offer收割机&#xff01; 点击下方收割Offer 目录 01 基础查询 - SQL1 查询所有列 - SQL2 查询多列 - SQL3 查询结果去重 - SQL4 查询结果限制返回行数 - SQL5 将查询后的列重新命名 -…

【Linux篇】第十七篇——信号量

前言 POSIX信号量 信号量的概念 信号量的工作原理 信号量函数 二元信号量模拟实现互斥功能 基于环形队列的生产消费模型 空间资源和数据资源 生产者和消费者申请和释放资源 必须遵守的两个规则 代码实现 信号量保护环形队列的原理 前言 将可能被多个执行流同时访问…

spark yarn集群遇到的问题与解决方法

背景&#xff1a; 已经存在如下环境&#xff1a; Ambari 2.7.5 HDFS 3.2.1 YARN 3.2.1 HIVE 3.1.1 ON MapReduce2 3.2.2 新安装了 Spark2 2.4.8 提交spark任务到yarn集群&#xff0c;不能成功执行 Spark2.4.8遇到的问题与处理方式 错误&#…

C++基础知识梳理<2>(引用、内联函数、auto关键字) [入门级】

目录 一、引用 1. 引用概念 2. 引用特性 2.1 引用在定义时必须初始化 2.2 一个变量可以有多个引用 2.3 引用一旦引用一个实体&#xff0c;再不能引用其他实体 3. 常引用 3.1 取别名的规则 3.2 权限放大error 3.3 权限不变 3.4 权限缩小 4. 引用原理与拓展 4.1…

目标检测(6)—— YOLO系列V2

一、YOLOV2改进的概述 做的改进如下图&#xff1a; Batch Normalization 批量归一化层 不加BN层&#xff0c;网络可能学偏&#xff0c;加上归一化进行限制。 从今天来看&#xff0c;conv后加BN是标配。 更大的分辨率 V1训练的时候使用224224&#xff0c;测试用448448。 V2训…

重学数据库基础

幸福找到我&#xff0c;幸福说&#xff1a;“瞧这个诗人&#xff0c;他比我本人还要幸福” 一、数据库相关概念 数据库 存储数据的仓库&#xff0c;数据是有组织的进行存储英文&#xff1a;DataBase&#xff0c;简称 DB 数据库管理系统 管理数据库的大型软件英文&#xff1a;Da…

时间序列预测之为何舍弃LSTM而选择Informer?(Informer模型解读)

LSTM的劣势 Figure 1: (a) LSTF can cover an extended period than the short sequence predictions, making vital distinction in policy-planning and investment-protecting. (b) The prediction capacity of existing methods limits LSTF’s performance. E.g., startin…

【408】数据结构知识点(查漏补缺)

知识点大部分来自于王道课后习题中易出错知识及薄弱内容&#xff0c;有问题的地方欢迎朋友们指出&#xff0c;一起讨论学习。 第一、二、三章 1.同一个算法&#xff0c;实现语言的级别越高&#xff0c;执行效率越低&#xff1b; 2.顺序表是一种存储结构&#xff0c;与之对应的…

公众号网课查题-响应速度快

公众号网课查题-响应速度快 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 题库&#xff1a;题库后台&#xff08;点击跳转&…

C/C++之(一)洛谷刷题及洛谷评测

学习之路&#xff0c;长路漫漫&#xff0c;写学习笔记的过程就是把知识讲给自己听的过程。 前段时间我们的实验室进行纳新&#xff0c;准备了一些题目&#xff0c;由于之前很少刷题的缘故&#xff0c;在这次刷题的过程中出现了很多的纰漏与问题。同时&#xff0c;我们选用的洛谷…

基于微信小程序电影交流平台源码成品(微信小程序毕业设计)

基于微信小程序电影交流平台 电影交流平台是基于java编程语言&#xff0c;mysql数据库&#xff0c;idea开发工具开发的后台&#xff0c;前端是微信小程序开发工具开发。本设计分为用户和管理员两个角色&#xff0c;其中用户可以登陆微信端&#xff0c;查看电影信息&#xff0c…

使用ping命令定位网络延迟问题

一、背景 使用ping命令发现局域网内延迟大&#xff0c;且变化较大。需要分析耗时在那一层。 二、方法论 从应用层到网络驱动层&#xff0c;监控数据流到达的时间。 但有一个问题&#xff0c;链路上运行的不一定只有ICMP数据包。因此&#xff0c;我们需要在每一层对我们实际和…

Helm简易安装使用

“ 若一个应用只有一个或几个这样的服务构成&#xff0c;那么确实足够。一旦应用变得复杂&#xff0c;那么配置文件就会变得十分繁多&#xff0c;几十个、上百个&#xff0c;这个时候的管理就会变得十分复杂&#xff0c;对于更新、回滚、修改、维护等需求就不太方便了。” Helm…

_cpp利用红黑树封装实现map和set

文章目录0. 前言1. 改造红黑树1.1 红黑树节点的定义1.2 红黑树中的迭代器1.2.1 模拟实现前置加加的方法1.2.2 模拟实现前置减减的方法1.2.3 红黑树迭代器代码1.3 仿函数1.4 红黑树整体改造完成后的代码2. 封装实现map3. 封装实现set4. 测试案例5. 测试结果0. 前言 链接&#x…

【网络篇】如何在服务器之间建立互信

引言 平时在服务器之间传输文件&#xff0c;常常需要确认并输入密码&#xff0c;非常繁琐。而服务器之间建立互性&#xff0c;就可以省去这个环节&#xff0c;方便快捷。 环境准备 我以两台服务器rac1和rac2为例说明。 名称公网私网rac1192.168.189.10192.168.83.10rac2192.1…

java计算机毕业设计ssm信息科技知识交流学习平台

项目介绍 通篇文章的撰写基础是实际的应用需要&#xff0c;然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程&#xff0c;以信息科技知识交流学习的实际应用需要出发&#xff0c;架构系统来改善现信息科技知识交流学习工作流程繁琐等问题。不仅如此…

2022人工智能数学基础1-2(许志钦

许老师 2017年 计算神经科学 博士后&#xff0c;转行做deep learning 神经元只是区分信号有无 单层神经网络 线性拟合&#xff1a; 数据、有模型、算未知参数a,b 最小二乘 定义 损失函数&#xff0c; 没有平方无法真正表征距离 求β&#xff0c; 方法一、最小化损失函数…
最新文章