首页 > 编程语言 >JavaEE 第1节 认识多线程

JavaEE 第1节 认识多线程

时间:2024-08-04 10:54:46浏览次数:12  
标签:Runnable run Thread 认识 创建 JavaEE 线程 进程 多线程

本节目标(全是重点,都必须掌握)

1、了解什么是线程、多线程、进程以及他们之间的关系

2、了解多线程的优势以及各种特性

3、用Java掌握多种创建线程的方法

一、线程、多线程、进程

1、概念

1.基本概念

这三个名词的概念可以用一个餐馆的厨房和厨师来进行超级形象的比喻

想象一下一个餐馆的厨房

整个厨房就是一个进程(Process)。这个厨房就是负责给前台客户提供各种菜品的进程。

厨房里得要有厨师吧,“厨房”里的“厨师”就叫做线程(Thread)

如果是一个大型酒店,厨房里的厨师肯定不止一位对吧,那么如果一个厨房里的厨师有好几位,既一个进程里又好几个线程,那么这就叫做多线程。

每一个厨师在厨房可以独自完成自己的任务,这就叫做线程的独立性

每一个厨师在厨房可以同时工作(做自己的菜),这就叫做线程的并行性线程之间是并发执行的

但是每一个厨师都在同一个厨房进行工作(同一个进程),公用一套厨具,一个厨师(线程)如果在用面包机,另一个厨师(线程)可能就不能用了(主要取决于“厨房”获得的资源大小),这就叫做同一进程中的所有线程,资源是共享的。

2.线程、多线程、进程之间的区别

我们在梳理一下刚才所讲的比喻:

厨房——>进程

厨师——>线程

一个厨房多个厨师——>多线程

  • 所以一个进程至少包含一个线程,既主线程。
     
  • 不同的进程之间是不共享资源的(比如硬盘,网络资源等),但是一个进程中的每一个线程共享同一份资源。
     
  • 线程是系统进行任务调度的最小单位。
     
  • 进程是系统进行资源分配的最小单位。
     
  • 一个进程挂了一般不会影响其他进程的正常运行,但是一个进程中的一个线程挂了,可能会影响到这个进程的正常运行!
     
  • 任意一个线程,都可以在创建一个新的线程。
     
  • 线程分为前台线程和后台线程,所有前台线程结束,整个进程才会结束,后台线程的结束,不会影响到进程的运行

注意:前台线程和后台线程除了是否能决定进程能否退出,在其他方面没有任何区别。

2、多线程的优点

首先,还是用刚才厨房和厨师的例子,假如说一个餐厅的客人非常的多,但是这么大的后厨,和这么多的需求只有一个厨师在卖命的炒菜,这显然是会被人骂的,餐厅早晚会倒闭。

为了充分利用厨房的各种资源,把每个厨具都用上,提高出餐效率,就可以请做个厨师同时进行工作。

既,充分利用进程所申请到的硬件资源(尤其是cup内核),多线程并发执行,高效完成任务,避免资源的浪费。

其次,虽然多进程也是可以实现并发编程的,但是进程的创建、调度、销毁速度远远慢与线程。既,线程更加轻量。

二、线程的创建方式

在java中创建线程,首先要了解一个类(Thread)和一个函数式接口(Runnable)

他们都有一个run()方法(Runnable的runf方法是抽象的,Thread的run方法是具体的),想要创建线程,就必须重写这个run()方法,然后把对象赋值给Thread类,通过Thread类的start()方法创建线程。

方式1——继承Thread:

class MyThread extends Thread{
    @Override
    public void run(){
        while(true){
            System.out.println("MuCreate");
        }
    }
}

public class Threads {
    public static void main(String[] args) {

        MyThread t1=new MyThread();
        t1.start();

        while(true){
            System.out.println("主线程执行");
        }
    }
}

运行结果(截取部分)

以上是通过继承的方式。

Thread类有几个构造方法我们必须了解(等一下还会用到一个哦):

方式2——实现Runnable:

Runnable是一个函数式接口,只包含run这一个抽象方法(注意,Thread类中的run是一个具体的方法)

什么是函数式接口?

1、只包含一个抽象方法

2、可以有默认方法、静态方法(jdk8后引入)

3、和普通接口一样定义的变量必须初始化并且默认被public static final修饰

4、可以用@FunctionalInterface来检查其准确性

因此我们需要实现Runnable才能重写run方法:

class MyThread implements Runnable {//实现并重写run
    
    @Override
    public void run() {
        while (true) {
            System.out.println("MuCreate");
        }
    }
}

public class Threads {
    public static void main(String[] args) {

        /*下面两种创建方式都可以*/
            //MyThread MyT=new MyThread();
            //Thread t1=new Thread(MyT);//把接口对消给到Thread的构造方法
        
        Thread t1 = new Thread(new MyThread());//把接口对消给到Thread的构造方法
        t1.start();

        while (true) {
            System.out.println("主线程执行");
        }
    }
}

运行结果这里不演示了,和Thread的一样。

注意:

1)对于main方法,系统会自动创建一个线程,这个线程叫主线程

2)只有在调用了Thread对象的start方法,才会创建线程,如果调用run方法,那么run方法里的程序实际上是在主线程上运行的。

3)通过start方法创建的线程默认是前台线程(所有前台线程结束JVM才会退出,同时不论后台线程有没有结束,后台线程也会自动退出)

除了以上两种创建线程的方式,下面还有三种创建线程的方法需要学习,都需要学习掌握。

不过不用怕,下面这三种方式本质上没有区别,都是用到的Thread的这个构造方法:

方式3——匿名内部类之Runnable:

本质就是方式2,既用一个类实现Runnable,不过方式3的这个类没有名字。

     Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("我是手动创建的线程");
            }
        };

这段代码的含义是先创建一个匿名内部类,这个匿名内部类实现了Runnable接口,并且重写了run方法。然后把创建好的匿名内部类对象,重新赋值给了runnable,既向上转型。

然后再创建Thread类,调用刚才给的构造方法即可:

        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("我是手动创建的线程");
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();

当然也可以在Thread的构造方法中直接进行匿名内部类的编写,省去runnable的创建:

  Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("我是手动创建的线程");
                }

            }
        });
        thread.start();

这样写的话代码的内聚性更强。
 

方式4——匿名内部类之Thread

本质就是方式1,既用一个类继承Thread,不过方式4的这个类没有名字。

     Thread thread = new Thread(){
            @Override
          public void run(){
                while(true){
                    System.out.println("创建的线程");
                }
            }
        };
        thread.start();
        while(true){
            System.out.println("主线程");
        }

方式5——匿名内部类之lambda

方式5的创建和方式3其实是一样的,不过这里换成了lambda表达式

通过lambda表达式重写run方法,并创建一个Runnable的对象,通过赋值的方式,传递给Thread

类的构造方法。

   Thread thread = new Thread(() -> {
                //下面直接编写方法体
            while (true) {
                System.out.println("hehe");
            }
        });

        thread.start();

除了这几种,实际上还可以使用Callable\Excuters创建,以后都会学习到,这里先做一个了解即可。


不论是那种创建方式,都需要重写run()方法,run()方法相当于线程入口。

并且都必须通过Thread类调用start()方法才能启动线程,如果调用run()方法是不会创建线程的,它会仍然在主线程中运行run()方法中的程序。

注意:

start()创建的线程,默认都是前台线程,如果不进行命名,默认按照Thread-0、Thread-1这种方式进行取名。


标签:Runnable,run,Thread,认识,创建,JavaEE,线程,进程,多线程
From: https://blog.csdn.net/2301_80636143/article/details/140492109

相关文章

  • Java通过redis实线多线程多用户操作时添加锁
    背景由于项目中多出涉及同步数据,同步过程就是从设备上查询数据,将数据库中该设备数据删除,将新数据导入到数据库;多次同步数据或多用户操作,会导致数据库出现重复数据,例如,两个线程同时删除设备数据,同时导入数据,就会出现双倍数据;还有线程1正在导入数据,中途线程2将线程1导入数据之前删......
  • Java使用多线程池给List赋值导致List存在空的处理
    错误示例:publicList<String>test()throwsNuMaxCloudCommonException{ExecutorServiceexecutorService=Executors.newFixedThreadPool(3);List<String>list=newArrayList<>();for(inti=0;i<3;i++){......
  • 【MATLAB源码】数学建模基础教程---初步认识数学建模
    系列文章目录在最后面,各位同仁感兴趣可以看看!什么是数学建模含义1.区分数学模型和数学建模2.建立数学模型的注意事项3.数学建模流程图解4.数学建模模型分类5.论文常用套路6.最后:总结系列文章目录含义所谓数学建模,简言之,就是对研究对象进行系统的抽象和概化,进而形成数学......
  • 【QT】Qt 多线程
    多线程qt多线程1.Qt多线程概述2.QThread常用API3.使用线程4.线程安全(1)互斥锁(2)条件变量(3)信号量qt多线程1.Qt多线程概述在Qt中,多线程的处理⼀般是通过QThread类来实现。QThread代表⼀个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享......
  • 多线程编程
    目录思维导图:学习内容:1. 多线程基本概念2.多线程编程2.1 pthread_create:创建线程 2.2 pthread_self线程号的获取2.3 pthread_exit:线程退出函数课外作业:1、使用两个线程完成两个文件的拷贝,分支线程1拷贝前一半,分支线程2拷贝后一半,主线程回收两个分支线程的资......
  • x264 中多线程相关编码参数详细介绍
    多线程编码相关参数参数名称参数类型参数含义cpuuint32_tcpu型号i_threadsint并行编码线程数i_lookahead_threadsint在lookahead分析中使用多线程b_deterministicint当开启多线程时是否允许非确定性优化b_sliced_threadsint是否使用基于......
  • 使用snapshot_download配置代理多线程下载模型
    snapshot_downloadhuggingface官方提供了snapshot_download方法下载完整模型,参数众多、比较完善。支持断点续传、多线程、指定路径、配置代理、排除特定文件等功能。然而有两个缺点:1))该方法依赖于transformers库,而这个库是个开发用的库,对于自动化运维有点重;2)该方法调用......
  • Java多线程编程详解:从基础到高级
    Java多线程编程详解:从基础到高级大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Java的多线程编程允许程序同时执行多个任务,提高了应用的性能和响应能力。本文将从基础到高级,全面介绍Java中的多线程编程,包括线程的创建、线程池、同步机制及并发工具的使用......
  • JavaSE基础 (认识String类)
    一,什么是String类在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想,而字符串应用又非常广泛,因此Java语言专门提供了Strin......
  • java 多线程简单实现
    Java实现多线程的方式在java中实现多线程有四种方式,如下:1、继承Thread类2、实现Runnable接口3、使用FutureTask4、使用Executor框架2、继承Thread类Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Th......