• 面试题:Java中创建线程有哪些方式?——全面解答(7种)


    目录

    Java中创建线程有哪些方式?

    方式一:继承Thread,重写run

    方式二:实现Runnable接口,重写run

    方式三:使用匿名内部类,实现创建Thread子类

    方式四:使用匿名内部类,实现Runnable接口

    方式五:lambda表达式——推荐使用

    方式六:Callable和Future接口创建并启动线程

    方式七:使用线程池


    Java中创建线程有哪些方式?

    方式一:继承Thread,重写run

    1、定义Thread类的子类MyThread,重写run()方法【线程执行体、就是线程要执行的任务】。

    2、创建MyThread类的实例

    3、调用子类实例的start()方法来启动线程

    1. class MyThread extends Thread {
    2. @Override
    3. public void run() {
    4. while(true) {
    5. System.out.println("thread");
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. }
    13. }
    14. public class Test1 {
    15. public static void main(String[] args) {
    16. MyThread myThread = new MyThread();
    17. myThread.start();//执行这个的同时,也会继续向下执行
    18. //并发
    19. while(true) {
    20. System.out.println("main");
    21. try {
    22. Thread.sleep(1000);
    23. } catch (InterruptedException e) {
    24. throw new RuntimeException(e);
    25. }
    26. }
    27. }
    28. }

            注:输出的thread和main大致上是交替输出,但说到底也不是严格的交替,因为无法确定哪个先执行,所以也会出现连续输出两个main或者thread,然后输出另一个 


    方式二:实现Runnable接口,重写run

     1、定义Runnable接口的实现类,必须重写run()方法,这个run()方法和Thread中的run()方法一样,是线程的执行体

    2、创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象

    3、调用start()方法

    1. class MyRunnable implements Runnable {
    2. @Override
    3. public void run() {
    4. while(true) {
    5. System.out.println("Thread");
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. }
    13. }
    14. public class Test2 {
    15. public static void main(String[] args) {
    16. MyRunnable myRunnable1 = new MyRunnable();
    17. Thread thread = new Thread(myRunnable1);
    18. thread.start();
    19. while(true) {
    20. System.out.println("main");
    21. try {
    22. Thread.sleep(1000);
    23. } catch (InterruptedException e) {
    24. throw new RuntimeException(e);
    25. }
    26. }
    27. }
    28. }

    方式三:使用匿名内部类,实现创建Thread子类

    类比于方式一 

    1. public class Test3 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread() {
    4. @Override
    5. public void run() {
    6. while (true) {
    7. System.out.println("Thread");
    8. try {
    9. Thread.sleep(1000);
    10. } catch (InterruptedException e) {
    11. throw new RuntimeException(e);
    12. }
    13. }
    14. }
    15. };
    16. thread.start();
    17. while(true) {
    18. System.out.println("main");
    19. try {
    20. Thread.sleep(1000);
    21. } catch (InterruptedException e) {
    22. throw new RuntimeException(e);
    23. }
    24. }
    25. }
    26. }

    方式四:使用匿名内部类,实现Runnable接口

    类比于方式二 

    1. public class Test4 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread(new Runnable(){
    4. @Override
    5. public void run() {
    6. while(true) {
    7. System.out.println("Thread");
    8. try {
    9. Thread.sleep(1000);
    10. } catch (InterruptedException e) {
    11. throw new RuntimeException(e);
    12. }
    13. }
    14. }
    15. });
    16. thread.start();
    17. while(true) {
    18. System.out.println("main");
    19. try {
    20. Thread.sleep(1000);
    21. } catch (InterruptedException e) {
    22. throw new RuntimeException(e);
    23. }
    24. }
    25. }
    26. }

    方式五:lambda表达式——推荐使用

    1. public class Test5 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread(()->{
    4. while(true) {
    5. System.out.println("Thread");
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. throw new RuntimeException(e);
    10. }
    11. }
    12. });
    13. thread.start();
    14. while(true) {
    15. System.out.println("main");
    16. try {
    17. Thread.sleep(1000);
    18. } catch (InterruptedException e) {
    19. throw new RuntimeException(e);
    20. }
    21. }
    22. }
    23. }

    方式六:Callable和Future接口创建并启动线程

    步骤如下:

    1、创建Callable接口实现类,并实现call()方法,该方法将作为线程执行体,且该方法有返回值,再创建Callable实现类的实例;
    2、使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
    3、使用FutureTask对象作为Thread对象的target创建并启动新线程;
    4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

    1. public class MyCallable implements Callable {
    2. @Override
    3. public String call() throws Exception {
    4. System.out.println("实现Callable接口方式");
    5. return "返回值"; // 返回值,类型和Callable泛型一致,这里用String举例
    6. }
    7. public static void main(String[] args) {
    8. // 创建Callable实现类对象
    9. MyCallable callable = new MyCallable();
    10. // 将callable作为参数创建FutureTask对象
    11. FutureTask futureTask = new FutureTask<>(callable);
    12. // 将futureTask作为参数创建线程
    13. Thread thread = new Thread(futureTask);
    14. thread.start(); // 启动线程
    15. try {
    16. // 获取线程执行后的返回值
    17. String result = futureTask.get();
    18. System.out.println(result);
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. }
    22. }
    23. }

    方式七:使用线程池

    通过Executor 的工具类可以创建三种类型的普通线程池

    a.FixThreadPool(int n);固定大小的线程池
    使用于为了满足资源管理需求而需要限制当前线程数量的场合。使用于负载比较重的服务器。

    1. import java.util.concurrent.ExecutorService;
    2. import java.util.concurrent.Executors;
    3. public class Test {
    4. public static void main(String[] args) {
    5. ExecutorService ex=Executors.newFixedThreadPool(5);
    6. for(int i=0;i<5;i++) {
    7. ex.submit(new Runnable() {
    8. @Override
    9. public void run() {
    10. for(int j=0;j<10;j++) {
    11. System.out.println(Thread.currentThread().getName()+j);
    12. }
    13. }
    14. });
    15. }
    16. ex.shutdown();
    17. }
    18. }

    b.SingleThreadPoolExecutor:单线程池
    需要保证顺序执行各个任务的场景

    1. import java.util.concurrent.ExecutorService;
    2. import java.util.concurrent.Executors;
    3. public class Test {
    4. public static void main(String[] args) {
    5. ExecutorService ex=Executors.newSingleThreadExecutor();
    6. for(int i=0;i<5;i++) {
    7. ex.submit(new Runnable() {
    8. @Override
    9. public void run() {
    10. for(int j=0;j<10;j++) {
    11. System.out.println(Thread.currentThread().getName()+j);
    12. }
    13. }
    14. });
    15. }
    16. ex.shutdown();
    17. }
    18. }

    c.CashedThreadPool(); 缓存线程池
    当提交任务速度高于线程池中任务处理速度时,缓存线程池会不断的创建线程
    适用于提交短期的异步小程序,以及负载较轻的服务器

    1. import java.util.concurrent.ExecutorService;
    2. import java.util.concurrent.Executors;
    3. public class Test {
    4. public static void main(String[] args) {
    5. ExecutorService ex=Executors.newCachedThreadPool();
    6. for(int i=0;i<5;i++) {
    7. ex.submit(new Runnable() {
    8. @Override
    9. public void run() {
    10. for(int j=0;j<10;j++) {
    11. System.out.println(Thread.currentThread().getName()+j);
    12. }
    13. }
    14. });
    15. }
    16. ex.shutdown();
    17. }
    18. }

    注意:多数情况下使用线程池来创建线程

    下期见!!! 

  • 相关阅读:
    设计模式学习笔记 - 设计原则 - 2.开闭原则
    监控办公室电脑用什么软件?
    你所不知道的实用类
    SSM+线上诊疗系统 毕业设计-附源码161711
    c++ 二元运算符重载, 以加法为例
    Windows使用进程监视器查看进程读写的文件名
    IDEA下新建SpringBoot项目详细步骤
    在云服务器中搭建MQTT平台
    C++ 类和对象
    【Element UI】解决 el-button 禁用状态下,el-tooltip 提示不生效问题
  • 原文地址:https://blog.csdn.net/LYJbao/article/details/126605012