• Java并发编程之多线程实现方法


    Java实现多线程的方式有比较多,但究其本质,最终都是在执行Thread的run方法,这个后文再作解释。下面先看看各种实现方式。

    实现 Runnable 接口

    1. public class RunnableThread  implements Runnable{
    2.    @Override
    3.    public void run() {
    4.        System.out.println("Runnable接口实现线程");
    5.   }
    6.    public static void main(String[] args) {
    7.        new Thread(new RunnableThread()).start();
    8.   }
    9. }

    通过实现 Runnable 接口实现多线程,只需要重写run接口,然后将Runnable实例传递给Thread类,调用start即可启动线程。

    继承 Thread 类

    1. public class ExtendsThread extends Thread {
    2.    @Override
    3.    public void run() {
    4.        System.out.println("用Thread类实现线程");
    5.   }
    6.    public static void main(String[] args) {
    7.        new ExtendsThread().start();
    8.   }
    9. }

    继承 Thread 类实现多线程,这种方式直接重写Thread类的run方法,同样通过start方法启动多线程。

    线程池创建线程

    还可以通过线程池创建线程,方式参考如下

    1. /**
    2. * @author kangming.ning
    3. * @date 2023-02-24 16:27
    4. * @since 1.0
    5. **/
    6. public class CustomThreadPool1 {
    7. private static ThreadFactory threadFactory = new ThreadFactoryBuilder().setNamePrefix("线程池-").build();
    8. private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
    9. Runtime.getRuntime().availableProcessors(),
    10. Runtime.getRuntime().availableProcessors() * 2,
    11. 60L,
    12. TimeUnit.SECONDS,
    13. new LinkedBlockingQueue<>(10),
    14. threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
    15. public static void main(String[] args) throws InterruptedException {
    16. Runnable r = () -> {
    17. System.out.println(Thread.currentThread().getName() + " is running");
    18. };
    19. for (int i = 0; i < 35; i++) {
    20. Thread.sleep(1000);
    21. threadPoolExecutor.submit(r);
    22. }
    23. }
    24. }

    当然,也可以使用ExecutorService去管理线程池,这个方式和上面的没本质区别,ExecutorService实际也是使用ThreadPoolExecutor创建的线程池,如下:

    1. public class FixedThreadPool {
    2. public static void main(String[] args) {
    3. ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    4. for (int i = 0; i < 5; i++) {
    5. executor.execute(new RunnableThread());
    6. }
    7. executor.shutdown();
    8. }
    9. }
    10. public class RunnableThread implements Runnable {
    11. @Override
    12. public void run() {
    13. System.out.println("用实现Runnable接口实现线程,ThreadName:" + Thread.currentThread().getName());
    14. }
    15. }

    有返回值的 Callable 创建线程

    1. public class CallableTask implements Callable {
    2.    @Override
    3.    public Integer call() throws Exception {
    4.        return new Random().nextInt();
    5.   }
    6.    public static void main(String[] args) throws ExecutionException, InterruptedException {
    7.        //创建线程池
    8.        ExecutorService service = Executors.newFixedThreadPool(10);
    9.        //提交任务,并用Future提交返回结果
    10.        Future future = service.submit(new CallableTask());
    11.        Integer randomNumber = future.get();//此方法阻塞
    12.        System.out.println("randomNumber:"+randomNumber);
    13.        service.shutdown();
    14.   }
    15. }

    定时器 Timer

    1. public class TimerTest {
    2.    public static void main(String[] args) {
    3.        Timer timer=new Timer();
    4.        //延时0毫秒 每1秒执行一次
    5.        timer.schedule(new TimerTask() {
    6.            @Override
    7.            public void run() {
    8.                System.out.println("Timer线程,ThreadName:"+Thread.currentThread().getName());
    9.           }
    10.       },0,1000);
    11.   }
    12. }
    定时器Timer内部使用TimerThread处理定时任务,TimerThread继承于Thread类,于是,还是之前方式,只是包装了一下。
    
    

    线程实现原理源码探索

    通过上面的讲述,我们发现,看似有很多方式去实现多线程,但最终都需要通过Thread类,调用start方法,实现线程的开启。下面看一下Thread类的start方法

    1. /* What will be run. */
    2. private Runnable target;
    3. public synchronized void start() {
    4.        /**
    5.         * This method is not invoked for the main method thread or "system"
    6.         * group threads created/set up by the VM. Any new functionality added
    7.         * to this method in the future may have to also be added to the VM.
    8.         *
    9.         * A zero status value corresponds to state "NEW".
    10.         */
    11.        if (threadStatus != 0)
    12.            throw new IllegalThreadStateException();
    13.        /* Notify the group that this thread is about to be started
    14.         * so that it can be added to the group's list of threads
    15.         * and the group's unstarted count can be decremented. */
    16.        group.add(this);
    17.        boolean started = false;
    18.        try {
    19.            start0();
    20.            started = true;
    21.       } finally {
    22.            try {
    23.                if (!started) {
    24.                    group.threadStartFailed(this);
    25.               }
    26.           } catch (Throwable ignore) {
    27.                /* do nothing. If start0 threw a Throwable then
    28.                  it will be passed up the call stack */
    29.           }
    30.       }
    31.   }
    32.    
    33.    private native void start0();
    34.     @Override
    35.    public void run() {
    36.        if (target != null) {
    37.            target.run();
    38.       }
    39.   }

    可以看出,start方法最终会经由start0本地方法最终调用run方法。而run方法里面的target是一个Runnable对象,如果target不是空,就调用target的run方法。这就解释了为什么实现Runnable接口传递给Thread构造函数,最终能调用Runnable的run方法。如果我们用继承Thread重写run方法来实现线程,明显,start方法调用的run方法直接就是这个子类的run方法了。这样看来,实现多线程只有一种方法,就是构造Thread类,调用start方法,经由本地方法start0最终调用它的run方法。

    实现 Runnable 接口方式比继承 Thread 类方式好的理由

    • Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,Runnable负责跑任务
    • 可扩展 性更强,Java 语言不支持双继承,实现Runnable接口的类未来还可以继承别的类
  • 相关阅读:
    用pytorch实现神经网络
    MySQL安装与配置
    长短期记忆网络(LSTM)重点!(自己汇集了很多资料在这篇博客)
    【SQL】一篇带你掌握SQL数据库的查询与修改相关操作
    宋浩高等数学笔记(一)函数与极限
    对毕业季即将踏入职场的年轻人的一点建议
    js加密双重保障之sm2国密
    yarn install:unable to get local issuer certificate
    结巴(jieba)分词 java 实现
    JSP在线客户服务支持管理系统myeclipse开发mysql数据库bs框架java编程jdbc
  • 原文地址:https://blog.csdn.net/u012882823/article/details/140370991