为什么说本质上只有一种实现线程的方式?实现Runnable接口究竟比继承Thread类实现线程好在哪里?

1、实现Runnable接口

  1. public class RunnableThread implements Runnable {
  2. @Override
  3. public void run() {
  4. Sysout.out.print("用实现Runnable接口实现线程");
  5. }
  6. }

通过实现Runnable 接口的方式实现多线程

  • 首先通过RunnableThread类实现Runnable接口
  • 然后重写了run()方法
  • 之后只要把这个实现了run()方法的实例传到Thread类中就可以实现线程

    2、继承Thread类

    1. public class ExtendsThread extends Thread {
    2. @Override
    3. public void run() {
    4. Sysoutl.out.print("用Thread类实现线程")
    5. }
    6. }
  • 与第一种方法不同的是 它没有实现接口,而是继承Thread类,并重写了其中的run()方法

    3、线程池创建线程

    1. static class DefaultThreadFactory implements ThreadFactory {
    2. private static final AtomicInteger poolNumber = new AtomicInteger(1);
    3. private final ThreadGroup group;
    4. private final AtomicInteger threadNumber = new AtomicInteger(1);
    5. private final String namePrefix;
    6. DefaultThreadFactory() {
    7. SecurityManager s = System.getSecurityManager();
    8. group = (s != null) ? s.getThreadGroup() :
    9. Thread.currentThread().getThreadGroup();
    10. namePrefix = "pool-" +
    11. poolNumber.getAndIncrement() +
    12. "-thread-";
    13. }
    14. public Thread newThread(Runnable r) {
    15. Thread t = new Thread(group, r,
    16. namePrefix + threadNumber.getAndIncrement(),
    17. 0);
    18. if (t.isDaemon())
    19. t.setDaemon(false);
    20. if (t.getPriority() != Thread.NORM_PRIORITY)
    21. t.setPriority(Thread.NORM_PRIORITY);
    22. return t;
    23. }
    24. }
  • 默认是采用DefaultThreadFactory

  • 它会给我们线程池创建的线程设置一些默认的值,比如他的名字,是不是守护线程,以及它的优先级

    4、有返回值的Callable

    1. class CallableTask implements Callable<Integer> {
    2. @Override
    3. public Integer call() throws Exception{
    4. return new Random().nextInt();
    5. }
    6. }
    7. //创建线程池
    8. ExecutorService service = Executor.newFixedThreadPool(10);
    9. // 提交任务 并用Future 提交返回结果
    10. Future<Intgeger> future = service.submit(new CallableTask());
  • 有返回值的callable也是一种新建线程的方式

    5、其他创建方式

    比如 定时器Timer
    TimerTask的实现了Runnable接口,Timer内部有个TimerThread继承自Thread因此绕回来还是Thread
    匿名内部类

  • 他不是传入一个已经实例好的runnable对象,而是直接在这边去用一个匿名内部类的方式把需要传入的runnable给实现出来 ``` new Thread(new Runnable(){ @Override public void run() {

    1. System.out.print(Thread.currentThread().getName());

    } }).start();

  1. Lambda表达式

new Thread(() -> System.out.print(Thread.currentThread().getName()); ) ```

  • 这些仅仅是表面层次的,实际上 事项方式那是那么2种

    6、实现线程本质上只有一种方式

    创建线程只有一种方式: 构造Thread类
    实现线程 “运行内容”有2种方式

  • 实现Runnable接口的run方式,并把Runnable实例作为target对象,传给Thread类,最终调用target.run()

  • 继承Thread类,重写Thread的run方法,Thread.start() 会执行run()

    7、Runnale接口与继承Thead类

    实现runnable接口要比继承thread类更好些

  • 可以把不同内容进行解耦,权责分明

  • 某些情况下可以提升性能,减小开销
  • 继承Thread类相当于限制了代码未来的可扩展性