• 实现多线程的4种方式


    实现多线程的4种方式

    使用实现多线程有四种方式:

    • 继承 Thread 类;

    • 实现 Runnable 接口;

    • 使用 Callable 和 FutureTask 实现有返回值的多线程;

    • 使用 ExecutorService 和 Executors 工具类实现线程池(如果需要线程的返回值,需要在线程中实现 Callable

      和 Future 接口)

    1.1 继承 Thread 类

    Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过

    Thread 类的 start() 实例方法,start() 方法是一个 native 方法,它将启动一个新线程,并执行 run() 方法。

    继承 Thread 类的优点:简单,且只需要实现父类的 run 方法即可( start 方法中含有 run 方法,会创建一个新的

    线程,而 run 是执行当前线程)。

    继承 Thread 类的缺点:Java 的单继承,如果对象已经继承了其他的类则不能使用该方法,且不能获取线程的返回

    值。

    package com.multithreading;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            MyThread1 myThread1 = new MyThread1();
            MyThread1 myThread2 = new MyThread1();
            myThread1.start();
            myThread2.start();
        }
    
    }
    
    class MyThread1 extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    # 程序输出
    Thread-1
    Thread-0
    
    • 1
    • 2
    • 3

    1.2 实现 Runnable 接口

    实现 Runnable 接口优点:简单,实现 Runnable 接口必须实现 run 方法。

    实现 Runnable 接口缺点:创建一个线程就必须创建一个 Runnable 的实现类,且不能获取线程的返回值。

    package com.multithreading;
    
    public class RunnableDemo {
        public static void main(String[] args) {
            System.out.println(Thread.currentThread().getName());
            Thread t1 = new Thread(new MyThread2());
            t1.start();
        }
    }
    
    class MyThread2 implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    # 程序输出
    main
    Thread-0
    
    • 1
    • 2
    • 3

    1.3 使用 Callable 和 FutureTask

    CallabTask 优点:可以获取多线程的返回值。

    CallabTask 缺点:每个多线程都需要创建一个 Callable 的实现类。

    package com.multithreading;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class CallableDemo {
    
        public static void main(String[] args) {
            FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
            new Thread(futureTask).start();
            try {
                String result = futureTask.get();
                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
    
    class CallerTask implements Callable<String> {
        @Override
        public String call() {
            return Thread.currentThread().getName();
        }
    }
    
    • 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
    # 程序输出
    Thread-0
    
    • 1
    • 2

    1.4 使用 ExecutorService 和 Executors

    线程池 ExecutorService 和工具类 Executors 优点:可以根据实际情况创建线程数量,且只需要创建一个线程池即

    可,也能够通过 Callable 和 Future 接口得到线程的返回值,程序的执行时间与线程的数量紧密相关。

    线程池 ExecutorService 和工具类 Executors 缺点:需要手动销毁该线程池(调用shutdown方法)。

    package com.multithreading;
    
    import java.util.concurrent.Callable;
    
    public class MyTask implements Callable<String> {
    
        private final int id;
    
        public MyTask(int id) {
            this.id = id;
        }
    
        @Override
        public String call() {
            return "result of TaskWithResult: " + id;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    package com.multithreading;
    
    import java.util.ArrayList;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class ExecutorServiceDemo {
    
        static final int NUMBER = 10;
    
        public static void main(String[] args) {
            ExecutorService exec = Executors.newCachedThreadPool();
            ArrayList<Future<String>> results = new ArrayList<>();
            for (int i = 0; i < NUMBER; i++) {
                results.add(exec.submit(new MyTask(i)));
            }
            exec.shutdown();
            for (Future<String> future : results) {
                try {
                    System.out.println(future.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 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
    # 程序输出
    result of TaskWithResult: 0
    result of TaskWithResult: 1
    result of TaskWithResult: 2
    result of TaskWithResult: 3
    result of TaskWithResult: 4
    result of TaskWithResult: 5
    result of TaskWithResult: 6
    result of TaskWithResult: 7
    result of TaskWithResult: 8
    result of TaskWithResult: 9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    MySQL update 是锁行还是锁表?
    细粒度图像分类论文研读-2016
    warning : ‘__ANDROID_API__‘ macro redefined [-Wmacro-redefined]
    展会预告丨中国海洋装备博览会盛大开幕!箱讯科技亮相1T18展位
    树莓派4b开机自启sh脚本
    uniapp初步搭建:如何引入uview库(跨移动多端ui库)
    怎样正确做 Web 应用的压力测试?
    Java 定时任务--Quartz框架
    BMZCTF phar???
    ThreadPoolExecutor源码分析
  • 原文地址:https://blog.csdn.net/qq_30614345/article/details/132389490