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

这篇具有很好参考价值的文章主要介绍了Java多线程(1)---多线程认识、四种创建方式以及线程状态。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一.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🙉
🎄 本章讲解内容:多线程的认识、创建方式、及其状态

Java多线程(1)---多线程认识、四种创建方式以及线程状态,JavaEE,java,学习,开发语言,java-ee

 

🎥学习专栏:  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多线程的生命周期

Java多线程(1)---多线程认识、四种创建方式以及线程状态,JavaEE,java,学习,开发语言,java-ee

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

1.4Java多线程的执行机制

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

Java多线程(1)---多线程认识、四种创建方式以及线程状态,JavaEE,java,学习,开发语言,java-ee

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


 

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

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对象创建线程对象,并命名

常见属性:

属性 获取方法
ID getId()
名称 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状态的抽象说明 

状态图: 

Java多线程(1)---多线程认识、四种创建方式以及线程状态,JavaEE,java,学习,开发语言,java-ee  

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

        多线程的概念、创建、状态的讲解本章已经结束了,而后期还有很多线程操作、线程安全、锁等知识,因此多线程是一个极为复杂并且重要的知识。文章来源地址https://www.toymoban.com/news/detail-625013.html

到了这里,关于Java多线程(1)---多线程认识、四种创建方式以及线程状态的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Java创建数组的四种方式

    1.使用默认值来初始化 语法: 数组元素类型 [] 数组名称 = new 数组元素类型 [数组长度] EG: int [] nums = new int [5]; //创建了一个类型为int,名字为nums ,长度为5的数组 2.先声明一个数组,再给值 语法: 数据元素类型 [] 数组名称; 数组名称 = new 数组元素类型[数组长度]; EG: int [] nums; num

    2024年02月09日
    浏览(61)
  • Java创建数组、赋值的四种方式,声明+创建+初始化 详解

    以int数据类型为例 注意: new 数据类型[]{},其中花括号可以省去,但要在[ ]中填写数组的个数; 创建多维数组时 new后面第一个方括号中的元素数量不能省略 1、一维数组的声明方式: type[] arrayName; 或 type arrayName[]; 推荐使用第一种格式,因为第一种格式具有更好的可读性,表

    2024年04月11日
    浏览(55)
  • 【JavaEE】JUC(java.util.concurrent)的常见类以及线程安全的集合类

    目录 1、JUC(java.util.concurrent)的常见类 1.1、Callable接口的用法(创建线程的一种写法)  1.2、ReentrantLock可重入互斥锁 1.2.1、ReentrantLock和synchronized的区别  1.2.2、如何选择使用哪个锁 1.3、Semaphore信号量 1.4、CountDownLatch  2、线程安全的集合类 2.1、多线程环境使用ArrayList  2.2、

    2024年02月07日
    浏览(46)
  • 【Java多线程】线程中几个常见的属性以及状态

    目录 Thread的几个常见属性 1、Id 2、Name名称 3、State状态 4、Priority优先级 5、Daemon后台线程 6、Alive存活   ID 是线程的唯一标识,由系统自动分配,不同线程不会重复。 用户定义的名称。该名称在各种调试工具中都会用到。 状态表示线程当前所处的一个情况。和进程一样,线程

    2024年02月19日
    浏览(42)
  • JavaEE:多线程(2):线程状态,线程安全

    目录 线程状态 线程安全 线程不安全 加锁 互斥性 可重入  死锁 死锁的解决方法  Java标准库中线程安全类 内存可见性引起的线程安全问题 等待和通知机制 线程饿死 wait notify 就绪:线程随时可以去CPU上执行,也包含在CPU上执行的线程 阻塞:这个线程暂时不方便去CPU上执行

    2024年01月23日
    浏览(45)
  • JUC并发编程-集合不安全情况以及Callable线程创建方式

    1)List 不安全 ArrayList 在并发情况下是不安全的 解决方案 : 1.Vector 2.Collections.synchonizedList() 3. CopyOnWriteArrayList 核心思想 是,如果有 多个调用者(Callers)同时要求相同的资源 (如内存或者是磁盘上的数据存储),他们 会共同获取相同的指针指向相同的资源 , 直到某个调用者

    2024年01月23日
    浏览(46)
  • Java多线程 - Java创建线程的4种方式

    1. Java创建线程有哪几种方式? 一个线程在Java中使用一个Thread实例来描述。Thread类是Java语言的一个重要的基础类,位于java.lang包中。Thread类有不少非常重要的属性和方法,用于存储和操作线程的描述信息。 Thread类的构造方法: 1.1 线程创建方法一:继承Thread类创建线程类 (

    2023年04月08日
    浏览(39)
  • JavaEE之多线程编程:3. 线程的状态(易懂!)

    进程 最核心的状态,一个是就绪状态,一个是阻塞状态(对于线程同样使用)。 以线程为单位进行调度的。 在Java中,又给线程赋予了一些其他的状态。 线程的状态是一个枚举类型 Thread.State 线程的状态一共有6个: NEW:安排了工作, 还未开始行动。(Thread对象已经有了,.

    2024年01月19日
    浏览(50)
  • 【JavaEE】_线程的状态与转移

    目录 1. 线程的状态 1.1 NEW 1.2 RUNNABLE 1.3 BLOCKED 1.4 WAITING 1.5 TIMED_WAITING 1.6 TERMINATED  2. 线程状态的转移 在多线程Thread类相关一文中已经介绍过进程的状态:就绪状态与阻塞状态; 若需详情请查看原文,链接如下: 【JavaEE】_多线程Thread类及其常用方法-CSDN博客 这个状态决定

    2024年02月22日
    浏览(32)
  • JavaEE 初阶篇-深入了解多线程等待与多线程状态

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 线程等待         1.1 线程等待 - join() 方法         1.1.1 main 线程中等待多个线程         1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程         1.1.3 其他线程阻塞等待 main 线程

    2024年04月17日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包