多线程创建方式详解

1. 多线程的创建的三种方式

多线程的创建主要有三种方式。

  • 继承Thread类(将任务和线程合并在一起)
  • 实现Runnable接口(将任务和线程分开了)
  • 实现Callable接口(利用FutureTask执行任务)

1.1. 继承Thread类

package com.asleepyfish;

/**
 * @Author: asleepyfish
 * @Date: 2022-02-28 21:44
 * @Description: 继承Thread类
 */
public class InheritThread extends Thread {
    
    
    private int num = 5;
    private final String name;

    public InheritThread(String name) {
    
    
        this.name = name;
    }

    @Override
    public void run() {
    
    
        while (num > 0) {
    
    
            System.out.println(name + "拿了第" + num-- + "张票");
            try {
    
    
                Thread.sleep(20);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
        InheritThread thread1 = new InheritThread("小明");
        InheritThread thread2 = new InheritThread("小华");
        thread1.start();
        thread2.start();
    }
}
第一次运行结果:
小华拿了第5张票
小明拿了第5张票
小明拿了第4张票
小华拿了第4张票
小华拿了第3张票
小明拿了第3张票
小明拿了第2张票
小华拿了第2张票
小明拿了第1张票
小华拿了第1张票
===================
第二次运行结果:
小华拿了第5张票
小明拿了第5张票
小明拿了第4张票
小华拿了第4张票
小华拿了第3张票
小明拿了第3张票
小华拿了第2张票
小明拿了第2张票
小华拿了第1张票
小明拿了第1张票

多线程的执行是乱序执行的,每次的结果也都是随机的。

1.2. 实现Runnable接口

package com.asleepyfish;

/**
 * @Author: asleepyfish
 * @Date: 2022-02-28 21:59
 * @Description: 实现Runnable接口
 */
public class RunnableThread implements Runnable {
    
    
    private int num = 5;

    @Override
    public void run() {
    
    
        while (num > 0) {
    
    
            System.out.println(Thread.currentThread().getName() + "拿了第" + num-- + "张票");
            try {
    
    
                Thread.sleep(20);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
    
    
    	// 这里还是new了两个RunnableThread对象,两个线程并不是操作同一个资源,没有实现资源共享
        new Thread(new RunnableThread(), "小明").start();
        new Thread(new RunnableThread(), "小华").start();
		// 如果只new了一个对象去执行会引发并发线程安全问题
		// RunnableThread runnableThread = new RunnableThread();
        // new Thread(runnableThread, "小红").start();
        // new Thread(runnableThread, "小强").start();
    }
}
第一次运行结果:
小明拿了第5张票
小华拿了第5张票
小华拿了第4张票
小明拿了第4张票
小明拿了第3张票
小华拿了第3张票
小华拿了第2张票
小明拿了第2张票
小华拿了第1张票
小明拿了第1张票
================
第二次运行结果:
小明拿了第5张票
小华拿了第5张票
小华拿了第4张票
小明拿了第4张票
小明拿了第3张票
小华拿了第3张票
小华拿了第2张票
小明拿了第2张票
小明拿了第1张票
小华拿了第1张票

1.3 实现Callable接口

package com.asleepyfish;

import java.util.concurrent.*;

/**
 * @Author: asleepyfish
 * @Date: 2022-03-01 21:57
 * @Description: 实现Callable接口
 */
public class CallableThread implements Callable<String> {
    
    
    private int step = 10;

    @Override
    public String call() {
    
    
        String result;
        while (step > 0) {
    
    
            System.out.println("还剩:" + step + "步");
            step--;
        }
        result = "走完了";
        return result;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
    
        CallableThread mc = new CallableThread();
        // 创建执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        // 提交执行
        Future<String> submit = executorService.submit(mc);
        // 获取结果
        String result = submit.get();
        System.out.println(result);
        // 关闭服务
        executorService.shutdown();
    }
}
还剩:10步
还剩:9步
还剩:8步
还剩:7步
还剩:6步
还剩:5步
还剩:4步
还剩:3步
还剩:2步
还剩:1步
走完了

2. 继承Thread和实现Runnable的区别

参考: Java多线程学习

继承Thread类,则不适合资源共享。实现Runable接口的话,很容易实现资源共享。

总结:

实现Runnable接口比继承Thread类所具有的优势

  1. 适合多个相同的程序代码的线程去处理同一个资源
  2. 可以避免java中的单继承的限制
  3. 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
  4. 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

main方法其实也是一个线程。在java中所有的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。

Supongo que te gusta

Origin blog.csdn.net/qq_41821963/article/details/123192943
Recomendado
Clasificación