• Java多线程详解、多线程的创建方式


    多线程

    什么是线程
    线程(thread)是一个程序内部的一条执行路径。我们之前启动程序执行后,main方法的执行其实就是一条单独的执行路径;程序中如果只有一条执行路径,那么这个程序就是单线程的程序。

    多线程是什么
    多线程是指从软硬件上实现多条执行流程的技术。

    方式一:继承Thread类

    Thread类
    Java是通过java.lang.Thread 类来代表线程的。

    实现流程

    1.定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法;
    2.创建MyThread类的对象;
    3.调用线程对象的start()方法启动线程(启动后还是执行run方法的);

    优缺点
    优点:编码简单
    缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,不便于扩展。

    示例代码

    public class ThreadDemo1 {
        public static void main(String[] args) {
            // 3、new一个新线程对象
            Thread t = new MyThread();
            // 4、调用start方法启动线程(执行的还是run方法)
            t.start();
    
            for (int i = 0; i < 5; i++) {
                System.out.println("主线程执行输出:" + i);
            }
    
        }
    }
    
    /**
       1、定义一个线程类继承Thread类
     */
    class MyThread extends Thread{
        /**
           2、重写run方法,里面是定义线程以后要干啥
         */
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.println("子线程执行输出:" + i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    方式二:实现Runnable接口

    实现流程

    1.定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法;
    2.创建MyRunnable任务对象;
    3.把MyRunnable任务对象交给Thread处理;
    4.调用线程对象的start()方法启动线程;

    Thread的构造器

    构造器说明
    public Thread(String name)为当前线程指定名称
    public Thread(Runnable target)封装Runnable对象成为线程对象
    public Thread(Runnable target ,String name )封装Runnable对象成为线程对象,并指定线程名称

    优缺点
    优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;
    缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的;

    示例代码

    public class ThreadDemo2 {
        public static void main(String[] args) {
            // 3、创建一个任务对象
            Runnable target = new MyRunnable();
            // 4、把任务对象交给Thread处理
            Thread t = new Thread(target);
            // Thread t = new Thread(target, "1号");
            // 5、启动线程
            t.start();
    
            for (int i = 0; i < 10; i++) {
                System.out.println("主线程执行输出:" + i);
            }
        }
    }
    
    /**
       1、定义一个线程任务类 实现Runnable接口
     */
    class MyRunnable  implements Runnable {
        /**
           2、重写run方法,定义线程的执行任务的
         */
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("子线程执行输出:" + i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    代码优化(匿名内部类形式)

    1.可以创建Runnable的匿名内部类对象;
    2.交给Thread处理;
    3.调用线程对象的start()启动线程;

    示例代码

    public class ThreadDemo2Other {
        public static void main(String[] args) {
            Runnable target = new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println("子线程1执行输出:" + i);
                    }
                }
            };
            Thread t = new Thread(target);
            t.start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println("子线程2执行输出:" + i);
                    }
                }
            }).start();
    
            new Thread(() -> {
                    for (int i = 0; i < 10; i++) {
                        System.out.println("子线程3执行输出:" + i);
                }
            }).start();
    
            for (int i = 0; i < 10; i++) {
                System.out.println("主线程执行输出:" + i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    方式三:实现Callable、FutureTask接口

    Callable接口为JDK 5.0新增接口。

    方式一、二存在的问题

    它们重写的run方法均不能直接返回结果,不适合需要返回线程执行结果的业务场景;

    而通过方式三的Callable和FutureTask来实现多线程,可以得到线程执行的结果。

    实现流程

    1. 得到任务对象
      a.定义类实现Callable接口,重写call方法,封装要做的事情;
      b.用FutureTask把Callable对象封装成线程任务对象;
    2. 把线程任务对象交给Thread处理;
    3. 调用Thread的start方法启动线程,执行任务;
    4. 线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果;

    FutureTask的API
    在这里插入图片描述
    方式三优缺点
    优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强 ,可以在线程执行完毕后去获取线程执行的结果;
    缺点:编码复杂一点;

    代码示例

    public class ThreadDemo3 {
        public static void main(String[] args) {
            // 3、创建Callable任务对象
            Callable<String> call = new MyCallable(100);
            // 4、把Callable任务对象 交给 FutureTask 对象
            //  FutureTask对象的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread了
            //  FutureTask对象的作用2: 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
            FutureTask<String> f1 = new FutureTask<>(call);
            // 5、交给线程处理
            Thread t1 = new Thread(f1);
            // 6、启动线程
            t1.start();
    
    
            Callable<String> call2 = new MyCallable(200);
            FutureTask<String> f2 = new FutureTask<>(call2);
            Thread t2 = new Thread(f2);
            t2.start();
    
            try {
                // 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。
                String rs1 = f1.get();
                System.out.println("第一个结果:" + rs1);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            try {
                // 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。
                String rs2 = f2.get();
                System.out.println("第二个结果:" + rs2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
        1、定义一个任务类 实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
     */
    class MyCallable implements Callable<String>{
        private int n;
        public MyCallable(int n) {
            this.n = n;
        }
    
        /**
           2、重写call方法(任务方法)
         */
        @Override
        public String call() throws Exception {
            int sum = 0;
            for (int i = 1; i <= n ; i++) {
                sum += i;
            }
            return "子线程执行的结果是:" + sum;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    总结

    在这里插入图片描述

  • 相关阅读:
    MyBatis
    Linux下基于GTK人脸识别界面设计
    ​怎么安全无损地将操作系统转移到固态硬盘?
    table边框改为细线
    肝癌来时“静悄悄”?早期肝癌为什么不会痛?一文读懂→
    flask 自定义命令 sqllite /SQLAlchemy 简单使用
    SpringBoot实现SSE构建实时数据单向推送
    day8-机器学习模型评估
    《C++ Primer》练习9.43-练习9.46:替换字符串简写和插入前后缀
    遥感高光谱笔记-高光谱遥感图像处理与信息提取
  • 原文地址:https://blog.csdn.net/weixin_52341477/article/details/125470467