Java多线程(1)---多线程认识、四种创建方式以及线程状态

news2024/9/28 15:27:31

目录

前言

一.Java的多线程

1.1多线程的认识 

1.2Java多线程的创建方式

1.3Java多线程的生命周期

1.4Java多线程的执行机制

二.创建多线程的四种方式

2.1继承Thread类

⭐创建线程 

⭐Thread的构造方法和常见属性

 2.2.实现Runnable接口

⭐创建线程

⭐使用lambda表达式创建

2.3实现Callable接口创建多线程

⭐线程的创建

⭐Callable接口的特点

2.4通过线程池创建多线程

⭐创建线程


🎁个人主页:tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主
🎥 本文由 tq02 原创,首发于 CSDN🙉
🎄 本章讲解内容:多线程的认识、创建方式、及其状态

 

🎥学习专栏:  C语言         JavaSE       MySQL基础  

前言

        在学习多线程之前,我们必须了解什么是线程?作用是什么?而线程的知识又与进程有关系,因此我们需要先了解进程再去了解线程,这样才能更好的学习到多线程的知识。本文只是多线程的一部分,多线程涉及的知识点很多很多,锁啊、线程安全啊、CAS等知识,需要耐心学习。

进程学习:http://t.csdn.cn/I4uDU

线程学习:http://t.csdn.cn/AxYac

一.Java的多线程

1.1多线程的认识 

     多线程,从字面上理解,就是从多个单线程一起执行多个任务。在Java 编程中,已经给多线程编程提供了内置的支持。多线程是多任务的一种特别的形式,但多线程使用了更小的cpu资源开销。 多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

        线程本身就是操作系统提供的概念,因此操作系统提供了一些API供程序员使用,而在Java中,也存在一些API供人们使用和编译。在Java标准库中Thread类就是用于多线程的创建。

注:创建多线程的方式不仅仅只有Thread类

1.2Java多线程的创建方式

Java语言中,目前可以创建多线程的方式有四种方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 使用lambda表达式(基于Runnable接口搭配内部类的优化)
  4. 使用线程池
  5. 使用FutureTask类和Callable接口

以上的1、2、5方法可以搭配匿名内部类使用,而目前最为常用的方式有:实现Runnable接口、调用多线程池。

1.3Java多线程的生命周期

         新建状态、可执行状态、执行状态以及死亡状态是每一个线程都会发生,而阻塞状态则是选择性发生,当需要阻塞时,使用sleep()、join()方法。

1.4Java多线程的执行机制

        当Java程序运行时,先创建出一个进程,该进程里至少包含一个线程主线程,就是负责执行main方法的线程。然后在mian()方法里创建出其他线程。我们主要学习的就是创建和使用线程。

 注:一般情况下,主线程与子线程相互不影响,即子线程结束,主线程不一定结束;主线程结束,子线程不一定结束;主线程异常,子线程不一定异常;子线程异常,主线程不一定异常。但当设置守护线程等特殊操作时,主线程与子线程会发生相互影响。


 

二.创建多线程的四种方式

2.1继承Thread类

⭐创建线程 

        使用Thread类创建线程有2种方式,最基本的实现多线程方式,就是创建一个类继承Thread类,然后再实例化该类。可实例化多个线程。

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

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

public class Text{
     public static void main(String[] args) {
        //创建MyThread实例
      MyThread t1=new MyThread();
       //调用start方法启动线程
     t1.start();
    }
}      

注:继承Thread类需要重写run()方法,而调用的是start()方法,而不是run()方法,start()是启动线程,而run()则是执行方法。

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

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

:该方法不需要继承其他类,而是直接实例化Thread类和使用匿名内部类。 

⭐Thread的构造方法和常见属性

Thread构造方法:

构造方法解释
Thread()创建线程
Thread(Runnable 对象名)使用Runnable对象创建线程
Thread(String 线程名)创建线程对象,并命名
Thread(Runnable 对象名,String 线程名)使用Runnable对象创建线程对象,并命名

常见属性:

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否有后台线程isDaemon()
是否存活isAlive()
是否中断isInterrupted()

ID 是线程的唯一标识,不同线程不会重复
名称是各种调试工具用到

其中重要的是前台和后台线程

  1. 前台线程,会影响到进程结束,如果前台进程没有执行完毕,进程不会结束
  2. 后台线程,也称守护线程,当主线程结束时,进程结束,后台线程无论是否还在执行也结束

 Java多线程当中默认为前台线程,也可以通过setDaemon方法设置,false

存活是指线程是否执行结束。中断是指让正在执行的线程强行结束。类似循环的break;


 2.2.实现Runnable接口

⭐创建线程

        Runnable接口,将需要执行的线程放入其中,再通过Runnable和Thread配合,就可以进行线程的实现。而方法有2种。

第一种:创建Thread类实例,调用构造方法时,将Runnable对象传参

class MyRunnable implements Runnable {
    @Override
    public void run() {
    System.out.println("这里是线程运行的代码");
    }
}
    
    //创建Thread类实例
Thread t = new Thread(new MyRunnable());
    //调用start()方法
    t.start();

        实现一个接口Runnable,然后重写run方法,再将Runnable实例化出的对象,放入Thread的构造函数Thread(Runnable 对象名),就可以实现线程的执行。

第二种:创建Thread类实例,搭配使用匿名内部类创建Runnable子类对象

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

        这种方法更为的简便,直接在匿名内部类当中重写run()方法,在run()方法内部写上需要执行的操作。

⭐使用lambda表达式创建

        lambda表达式用于匿名内部类和接口的情况,而创建Thread类时,搭配匿名内部类创建了Runnable子类对象,因此可以使用lambda表达式的方法简化操作。

lambda表达式的学习:http://t.csdn.cn/VxRLy

代码示例:

// 使用 lambda 表达式创建 Runnable 子类对象
Thread t4 = new Thread(() -> {
    System.out.println("使用匿名类创建 Thread 子类对象");
});

如果看不懂lambda表达式,你就记住这是一种创建线程的方法,不去理解。

注:相比前几种创建方式,使用lambda表达式创建更为方便简单。

2.3实现Callable接口创建多线程

⭐线程的创建

 Callable 是一个 interface . 使用时需要创建utureTask类的对象,相当于把线程封装了一个 "返回值". 方便程序猿借助多线程的方式计算结果.该方法是基于jdk5.0之后新增的方法,

方法步骤:

  1. 创建一个实现Callable接口的类。
  2. 在这个实现类中实现Callable接口的call()方法,并创建这个类的对象。       
  3. 将这个Callable接口实现类的对象作为参数传递到FutureTask类的构造器中,创建FutureTask类的对象。       
  4. 将这个FutureTask类的对象作为参数传递到Thread类的构造器中,创建Thread类的对象,并调用这个对象的start()方法。
  5. 在主线程中调用 futureTask.get() 能够阻塞等待新线程计算完毕. 并获取到 FutureTask 中的结
    果。

代码示例:

Callable<Integer> callable = new Callable<Integer>() {
        @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 1000; i++) {
        sum += i;
    }
    return sum;
    }
};
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
            t.start();
        int result = futureTask.get();
        System.out.println(result);

⭐Callable接口的特点

  1. Callable 和 Runnable 相对, 都是描述一个 "任务". Callable 描述的是带有返回值的任务,Runnable 描述的是不带返回值的任务.
  2. Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为
  3. Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定.
  4. FutureTask 就可以负责这个等待结果出来的工作.

2.4通过线程池创建多线程

        虽然创建销毁线程比创建销毁进程更轻量, 但是在频繁创建销毁线程的时候还是会比较低效.
线程池就是为了解决这个问题. 如果某个线程不再使用了, 并不是真正把线程释放, 而是放到一个 "池子"中, 下次如果需要用到线程就直接从池子中取, 不必通过系统来创建了.

⭐创建线程

1、线程池的使用,需要使用以下类: 

  • Executors 是一个工厂类, 能够创建几种不同风格的线程池.
  • ExecutorService 表示一个线程池实例.
  • ExecutorService 的 submit 方法能够向线程池中提交若干个任务.

2、Executors 创建的几种风格线程池:

实例化一个线程池格式:ExecutorService pool = Executors.方法();

创建线程池种类解释
 Executors.newFixedThreadPool(int  Num threads) 创建固定线程数的线程池
 Executors.newSingleThreadExecutor()创建只包含单个线程的线程池.
 Executors.newCachedThreadPool()创建线程数目动态增长的线程池.
 Executors.newScheduledThreadPool(int corePoolSize) 

设定延迟时间后执行命令,或者定期执行命令. 是

进阶版的 Timer.

注:Executors 本质上是 ThreadPoolExecutor 类的封装

代码示例:

ExecutorService pool = Executors.newFixedThreadPool(10);
    pool.submit(new Runnable() {
        @Override
    public void run() {
        System.out.println("hello");
    }
});
    //线程池使用结束之后需要使用shutdown()关闭
     pool.shutdown();

三.线程的状态

        线程的状态是一个枚举类型 Thread.State,而线程的状态一共有6种,6种状态定义在Thread类的State枚举中。

  1. 初始状态(NEW):线程对象被创建但尚未调用start()方法。
  2. 就绪状态(RUNNABLE):线程处于可运行线程池中,等待被线程调度选中获取CPU的使用权。就绪状态分为两种情况,一是线程对象创建后,其他线程调用了该对象的start()方法,此时线程处于某个线程拿到对象锁、当前线程时间片用完调用yield()方法、锁池里的线程拿到对象锁后,这些线程也将进入就绪状态。
  3. 运行状态(RUNNABLE之RUNNING):线程正在被执行,具体来说就是线程获得了CPU的使用权。
  4. 阻塞状态(BLOCKED):线程阻塞于锁,即线程在等待获得对象锁。
  5. 等待状态(WAITING):线程需要等待其他线程做出一些特定动作,比如等待其他线程的通知或中断。
  6. 超时等待状态(TIMED_WAITING):与等待状态不同的是,超过指定时间后会自动返回。
  7. 终止状态(TERMINATED):线程的run()方法执行完成,或者主线程的main()方法执行完成,线程终止。终止状态的线程不能再被复生。如果在终止状态的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

注:之前的 isAlive() 方法,可以认为是处于不是 NEW 和 TERMINATED 的状态都是活着

 

3.1状态的抽象说明 

状态图: 

  

  1. 初始状态(NEW):刚刚拿到银行卡
  2. 就绪状态(RUNNABLE):排队等待中
  3. 运行状态(RUNNABLE之RUNNING):开始与柜台人员进行交流取钱
  4. 阻塞状态(BLOCKED):阻塞了,相当于有人提前预约了取钱,你只能等待他结束
  5. 等待状态(WAITING):使用了wait()等待,例如柜台人员有一点事情,让你等到他回来
  6. 超时等待状态(TIMED_WAITING):使用了sleep(),柜台人员告诉了你等他多久;使用join()方法,就是你和你朋友同时在取钱,取钱到一半你说先停下来,我朋友那边取完了你再取。

        多线程的概念、创建、状态的讲解本章已经结束了,而后期还有很多线程操作、线程安全、锁等知识,因此多线程是一个极为复杂并且重要的知识。

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

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

相关文章

大一新生必读:如何选择适合自己的笔记本电脑?

大家好&#xff0c;这里是程序员晚枫&#xff0c; 今天给大家推荐5个适合大学生&#xff0c;尤其是大一新生使用的笔记本电脑。都是大品牌&#xff0c;而且价格实惠&#xff0c;性能优秀&#xff01; 偷偷说一句&#xff0c;点击本文链接有大额优惠券哟~ 01 推荐电脑 以下是…

【IC设计】ICC workshop Lab1 数据准备基本流程 【脚本总结】

Task 1 Create a Milkyway library 先进入lab1_data_setup目录&#xff0c;打开icc_shell&#xff0c;创建项目 create_mw_lib -technology $tech_file -mw_reference_library "$mw_path/sc $mw_path/io $mw_path/ram16x128" -bus_naming_style {[%d]} -open $my_m…

100道Python练习题

100道Python练习题&#xff0c;希望对你提升有所帮助&#xff01; 编写一个程序&#xff0c;输入两个数并计算它们的和。编写一个程序&#xff0c;输入一个字符串&#xff0c;并倒序输出该字符串。编写一个程序&#xff0c;判断一个数是否为质数。编写一个程序&#xff0c;计…

“Why Should I Trust You?” Explaining the Predictions of Any Classifier阅读笔记

“Why Should I Trust You?” Explaining the Predictions of Any Classifier阅读笔记 1. 论文贡献2. 背景 [ 1 ] ^{[1]} [1]3. LIME解释单个样本3.1 总体思想3.2 构建可解释的数据表示 [ 1 ] ^{[1]} [1]3.3 可解释性和忠实度的权衡3.4 局部采样3.5 稀疏线性解释3.6 使用SVM进…

C++ 一行代码删除string字符串中的“\n“、“\r“、“\t“ 和 所有空白字符

这篇博客记录如何删除C字符串中的回车、换行、制表符和所有的空白字符&#xff01; 方式一 示例&#xff1a; std::string str "\n\r\t abc \n\t\r cba \r\t\n"; std::cout << str << std::endl; 运行截图&#xff1a; 使用remove_if进行移除…

当我用Python采集全国加盟品牌详情信息,并进行可视化分析后发现了这些

表弟找我说想开个加盟店&#xff0c; 不知道什么品牌好&#xff0c;让我帮他参谋参谋。 还好我会Python&#xff0c;分分钟就获取到了全国加盟品牌信息&#xff0c;稍加分析就筛选出了最适合他的品牌。 话不多说&#xff0c;咱们直接分享干货&#xff01; 准备工作 开发环境…

第三章 API基础

3-1 String类 1、API概述-帮助文档的使用 【1】API概述 【2】如何使用帮助文档 2、键盘录入字符串案例 【1】需求 需求&#xff1a;按照帮助文档的使用步骤学习Scanner类的使用&#xff0c;并实现键盘录入一个字符串&#xff0c;最后输出在控制台 【2】实现 &#xff08;…

SuperNova论文赏析

1. 引言 前序博客有&#xff1a; Nova: Recursive Zero-Knowledge Arguments from Folding Schemes学习笔记 卡内基梅隆大学 Abhiram Kothapalli 和 微软研究中心 Srinath Setty 2022年论文《SuperNova: Proving universal machine executions without universal circuits》…

36.利用解fgoalattain 有约束多元变量多目标规划问题求解(matlab程序)

1.简述 多目标规划的一种求解方法是加权系数法&#xff0c;即为每一个目标赋值一个权系数&#xff0c;把多目标模型转化为一个单目标模型。MATLAB的fgoalattain()函数可以用于求解多目标规划。 基本语法 fgoalattain()函数的用法&#xff1a; x fgoalattain(fun,x0,goal,weig…

计蒜客T1116——验证子串

C实现验证子串的功能:今天复习了一下数据结构的串部分的内容&#xff0c;突然想起来子串匹配的实现&#xff0c;于是计蒜客随便找一道题写一下&#xff0c;核心的代码为裁剪子串和字符串比较两个内容&#xff0c;建议理解背诵&#xff0c;考研大概率会考。 子串裁剪 string Sf…

让这款音频转文字免费软件帮你解放双手吧

嘿&#xff0c;朋友们!你是不是经常遇到这样的场景——你听到一段精彩的演讲、音乐或者语音笔记&#xff0c;却又不方便手动输入文字&#xff1f;别担心&#xff0c;音频转文字技术将解救你出困境&#xff01;说到这&#xff0c;你是不是也对这项技术动心了呢&#xff1f;想知道…

dbfirst下让efcore生成的model继承于一个公共的类

&#xff09;1 Make entities inherit from a base class in Entity Framework Core DB First https://davecallan.com/make-entities-inherit-base-class-in-entity-framework-core-db-first/ 通过EF Core Power Tools vs扩展插件实现 1.1&#xff09;安装扩展Install the…

组织门户支持成员自主公开,快速搭建内容|ModelWhale 版本更新

大暑三秋近&#xff0c;林钟九夏移&#xff0c;ModelWhale 迎来新一轮的版本更新&#xff0c;期待为你带来更好的使用体验。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; • 新增 门户内容支持成员自主公开&#xff08;团队版✓ &#xff09; • …

uni、css——制作表格样式的模型

案例展示 这里以5列做展示&#xff08;可随意调节&#xff09; 案例代码 <view class"list"><view class"item" v-for"(item,index) in list" :key"index">1</view> <!-- 有内容 --><view clas…

Git 主要命令和操作流程(来自B站黑马)

其中 git 查看日志有好些参数&#xff0c;黑马总结了下&#xff0c;这里记录一下 git 1og--prettyoneline --a11 --graph --abbrev-commit oneline 就是在同一行显示&#xff0c;graph 是以层次关系显示, --abbrev-commit 是查看唯一标识符。那么这么长的命令&#xff0c;每次…

spring-boot-maven-plugin使用

spring-boot-maven-plugin这个插件有7个目标&#xff1a; spring-boot:build-image 使用构建包将应用程序打包到OCI映像中。 spring-boot:build-info 根据当前MavenProject spring-boot:help 显示有关spring-boot-maven插件的帮助信息。 调用mvn-spring-boot:help-Ddetailtr…

Spark写PGSQL分区表

这里写目录标题 需求碰到的问题格式问题分区问题&#xff08;重点&#xff09; 解决完整代码效果 需求 spark程序计算后的数据需要往PGSQL中的分区表进行写入。 碰到的问题 格式问题 使用了字符串格式&#xff0c;导致插入报错。 val frame df.withColumn("insert_t…

一语道破 python 迭代器和生成器

简而言之&#xff1a;迭代器是一个抽象化的概念&#xff0c;在python中表示访问数据集合中元素的一种方式&#xff1b;生成器也是一个抽象化的概念&#xff0c;在python 中&#xff0c;边循环边生成所需数据&#xff0c;是一种时间换空间的方法。从访问数据方式上来看&#xff…

应急响应-主机后门webshell的排查思路(webshell,启动项,隐藏账户,映像劫持,rootkit后门)

0x00 windows主机后门排查思路 针对主机后门windows&#xff0c;linux&#xff0c;在对方植入webshell后&#xff0c;需要立即响应&#xff0c;排查出后门位置&#xff0c;以及排查对外连接&#xff0c;端口使用情况等等 排查对外连接状态&#xff1a; 借助工具&#xff1a;p…

T31开发笔记:librtmp拉流测试

若该文为原创文章&#xff0c;转载请注明原文出处。 T31使用librtmp拉流并保存成FLV文件或H264和AAC文件。 librtmp编译在前面有教程&#xff0c;自行编译。 实现的目的是想要获取获取rtmp的AAC流并播放&#xff0c;实时双向对讲功能。 一、硬件和开发环境 1、硬件&#xff1…