学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • Java基础

  • Java集合

  • MySQL

  • Redis

  • JVM

  • 多线程

    • Java多线程-创建线程
      • Java多线程01-创建线程
        • 实现Runnable接口
        • 继承Thread类
        • 两种方法的对比
        • 两种方法的选择
        • 线程池
        • 小结
    • Java多线程-启动线程
    • Java多线程-停止中断线程
    • Java多线程-生命周期
    • Java多线程-Thread和Object
    • Java多线程-线程属性
    • Java多线程-线程异常
    • Java多线程-线程安全
    • Java多线程-死锁问题和解决方案
  • 计算机网络

  • Spring

  • Kafka

  • Elasticsearch

  • Python

  • 面试专题

  • 知识库
  • 多线程
旭日
2023-03-31
目录

Java多线程-创建线程

# Java多线程01-创建线程

实现多线程的两种方式

  • 方法一:实现Runnable接口
  • 方法二:继承Thread类

# 实现Runnable接口

public class RunnableStyle implements Runnable{

    public static void main(String[] args) {
        Thread thread = new Thread(new RunnableStyle());
        thread.start();
    }

    @Override
    public void run() {
        System.out.println("使用Runnable方式创建线程");
    }
}

# 继承Thread类

public class ThreadStyle extends Thread {

    @Override
    public void run() {
        System.out.println("继承Thread类实现线程");
    }

    public static void main(String[] args) {
        new ThreadStyle().start();
    }
}

# 两种方法的对比

实现Runnable接口和继承Thread类这两种方式都是重写了run()方法,并最终调用start()方法来新建线程。

两种方法的本质在于构件线程的时候是否传入trager对象:

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

而run()方法又会根据传入的对象执行不同结果:

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

方法一:最终调用target.run(); 方法二:run()整个都被重写

# 两种方法的选择

推荐使用实现Runnable接口方法来实现线程

  • 从代码架构角度:具体的任务(run方法)应该和“创建和运行线程的机制(Thread类)”解耦,用runnable对象可以实现解耦。
  • 使用继承Thread的方式的话,那么每次想新建一个任务,只能新建一个独立的线程,而这样做的损耗会比较大(比如重头开始创建一个线程、执行完毕以后再销毁等。如果线程的实际工作内容,也就是run()函数里只是简单的打印一行文字的话,那么可能线程的实际工作内容还不如损耗来的大)。如果使用Runnable和线程池,就可以大大减小这样的损耗。
  • 继承Thread类以后,由于Java语言不支持双继承,这样就无法再继承其他的类,限制了可扩展性。

# 线程池

线程池的本质还是新建Thread类这一种方式来创建线程,并非是实现多线程的另一种方式。

public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 1000; i++) {
            executorService.submit(new Task() {
            });
        }
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}

部分源码:

    static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

可见本质还是通过new Thread的方式来创建线程的。

# 小结

现在有如下的代码(相当于两种方法的混合体),那么执行结果是什么呢?

public class BothStyle {
    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();
    }
}

输出的结果是Thread,虽然我们通过Runnable方式传入了trager对象,但是由于使用Thread方式会重写run(),所以传入的对象并不会执行。

我们只能通过新建Thread类这一种方式来创建线程,但是类里面的run方法有两种方式来实现,第一种是重写run方法,第二种实现Runnable接口的run方法,然后再把该runnable实例传给Thread类。

#Java
上次更新: 2024/06/29, 15:13:44
垃圾回收相关概念
Java多线程-启动线程

← 垃圾回收相关概念 Java多线程-启动线程→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式