深入浅出Java多线程(一)之实现多线程的方式|8月更文挑战

268 阅读3分钟

为什么要掌握多线程

用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。对于多线程的重要性,相信也不需要过多的阐述,只要没有领悟透彻,面试官将会给予社会性的教育...别问我为什么知道!!

73b1c96587a4f285e0bd2aefd2a5029.jpg

创建多线程的方式

关于多线程的创建方式,网上的文档五花八门,各有各的说法,有2、4、6种等等,有带返回值的也有线程池等;到底有多少种呢,关于这个的解答,Oracle的官方文档中早已给出了答复。官方网档链接

There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread

  • 方法一:实现Runnable接口

    /**
     * Runnable方式实现多线程
     */
    public class RunnableStyle implements Runnable{
        @Override
        public void run() {
            System.out.println("实现了Runable方法");
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread(new RunnableStyle());
            thread.run();
        }
    }
    
  • 方法二:继承Thread类

    public class ThreadStyle extends Thread{
    
        @Override
        public void run() {
            System.out.println("继承Thread类实现多线程");
        }
    
        public static void main(String[] args) {
            new ThreadStyle().start();
        }
    }
    

实现优劣

方法一(实现Runnable接口)更好

  1. 从代码架构考虑,run方法对应一个具体的任务,应该与线程的创建与运行等线程机制(即Thread类)解耦,从解耦性考虑

  2. 资源节约,每次一个新的任务都需要新建一个独立的线程(继承Thread类),用实现Runnable方法可以利用线程池等机制

  3. 用继承Thread类,因为Java不支持多继承,所以该线程无法继承其他类,对业务上比较麻烦

  4. 源码角度,实现Runnable有一个判断,调用传入的Run方法;继承Thread类的话,是重写了整个Run方法(见上述源码)

        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
        }
    

思考(同时调用Runnable的run()和Thread的run()方法,会如何执行)

最终Thread方法会执行,从源码角度分析,虽然构造了Thread方法并传入了Runnable对象,但是因为Thread的实现方式又重写了run()方法,所以最终还是执行了Thread的重写run()方法。

public class BothRunnableThread {
 public static void main(String[] args) {
     new Thread(new Runnable() {
         @Override
         public void run() {
             System.out.println("运行了Runnable方法");
         }
     }){
         @Override
         public void run() {
             System.out.println("运行了Thread方法");
         }
     }.start();
 }
}

总结

  1. 创建线程可以分为两类,Oracle官方文档也是这么说的;
  2. 准确地说,创建线程只有一种方式——构造Thread类,而实现线程的执行单元有两种方式
    • 方法一:实现Runnable 接口的run方法,并把Runnable对象实例传给Thread类执行
    • 方法二:重写Thread类的run方法(继承Thread类)