死磕 Java线程系列之创建线程的8种方式
创始人
2025-03-18 22:51:32
0次

 

简介

创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗?

继承Thread类并重写run()方法

 

  1. public class CreatingThread01 extends Thread {  
  2.     @Override  
  3.     public void run() {  
  4.         System.out.println(getName() + " is running");  
  5.     }  
  6.     public static void main(String[] args) {  
  7.         new CreatingThread01().start();  
  8.         new CreatingThread01().start();  
  9.         new CreatingThread01().start();  
  10.         new CreatingThread01().start();  
  11.     }  
  12. } 

继承Thread类并重写run()方法,这种方式的弊端是一个类只能继承一个父类,如果这个类本身已经继承了其它类,就不能使用这种方式了。

实现Runnable接口

 

  1. public class CreatingThread02 implements Runnable {  
  2.     @Override  
  3.     public void run() {  
  4.         System.out.println(Thread.currentThread().getName() + " is running");  
  5.     }  
  6.     public static void main(String[] args) {  
  7.         new Thread(new CreatingThread02()).start();  
  8.         new Thread(new CreatingThread02()).start();  
  9.         new Thread(new CreatingThread02()).start();  
  10.         new Thread(new CreatingThread02()).start();  
  11.     }  
  12. } 

实现Runnable接口,这种方式的好处是一个类可以实现多个接口,不影响其继承体系。

匿名内部类

 

  1. public class CreatingThread03 {  
  2.     public static void main(String[] args) {  
  3.         // Thread匿名类,重写Thread的run()方法  
  4.         new Thread() {  
  5.             @Override  
  6.             public void run() {  
  7.                 System.out.println(getName() + " is running");  
  8.             }  
  9.         }.start();  
  10.         // Runnable匿名类,实现其run()方法  
  11.         new Thread(new Runnable() {  
  12.             @Override  
  13.             public void run() {  
  14.                 System.out.println(Thread.currentThread().getName() + " is running");  
  15.             }  
  16.         }).start();       
  17.         // 同上,使用lambda表达式函数式编程  
  18.         new Thread(()->{  
  19.             System.out.println(Thread.currentThread().getName() + " is running");  
  20.         }).start();  
  21.     }  
  22. } 

使用匿名类的方式,一是重写Thread的run()方法,二是传入Runnable的匿名类,三是使用lambda方式,现在一般使用第三种(java8+),简单快捷。

实现Callabe接口

 

  1. public class CreatingThread04 implements Callable {  
  2.     @Override  
  3.     public Long call() throws Exception {  
  4.         Thread.sleep(2000);  
  5.         System.out.println(Thread.currentThread().getId() + " is running");  
  6.         return Thread.currentThread().getId();  
  7.     }  
  8.     public static void main(String[] args) throws ExecutionException, InterruptedException {  
  9.         FutureTask task = new FutureTask<>(new CreatingThread04());  
  10.         new Thread(task).start();  
  11.         System.out.println("等待完成任务");  
  12.         Long result = task.get();  
  13.         System.out.println("任务结果:" + result);  
  14.     }  
  15. } 

实现Callabe接口,可以获取线程执行的结果,FutureTask实际上实现了Runnable接口。

定时器(java.util.Timer)

 

  1. public class CreatingThread05 {  
  2.     public static void main(String[] args) {  
  3.         Timer timer = new Timer();  
  4.         // 每隔1秒执行一次  
  5.         timer.schedule(new TimerTask() {  
  6.             @Override  
  7.             public void run() {  
  8.                 System.out.println(Thread.currentThread().getName() + " is running");  
  9.             }  
  10.         }, 0 , 1000);  
  11.     }  
  12. } 

使用定时器java.util.Timer可以快速地实现定时任务,TimerTask实际上实现了Runnable接口。

线程池

 

  1. public class CreatingThread06 {  
  2.     public static void main(String[] args) {  
  3.         ExecutorService threadPool = Executors.newFixedThreadPool(5);  
  4.         for (int i = 0; i < 100; i++) {  
  5.             threadPool.execute(()-> System.out.println(Thread.currentThread().getName() + " is running"));  
  6.         }  
  7.     }  
  8. } 

使用线程池的方式,可以复用线程,节约系统资源。

并行计算(Java8+)

 

  1. public class CreatingThread07 {  
  2.     public static void main(String[] args) {  
  3.         List list = Arrays.asList(1, 2, 3, 4, 5);  
  4.         // 串行,打印结果为12345  
  5.         list.stream().forEach(System.out::print);  
  6.         System.out.println();  
  7.         // 并行,打印结果随机,比如35214  
  8.         list.parallelStream().forEach(System.out::print);  
  9.     }  
  10. } 

使用并行计算的方式,可以提高程序运行的效率,多线程并行执行。

Spring异步方法

首先,springboot启动类加上@EnableAsync注解(@EnableAsync是spring支持的,这里方便举例使用springboot)。

 

  1. @SpringBootApplication  
  2. @EnableAsync  
  3. public class Application {  
  4.     public static void main(String[] args) {  
  5.         SpringApplication.run(Application.class, args);  
  6.     }  
  7. } 

其次,方法加上@Async注解。

 

  1. @Service  
  2. public class CreatingThread08Service {  
  3.     @Async  
  4.     public void call() {  
  5.         System.out.println(Thread.currentThread().getName() + " is running");  
  6.     }  
  7. } 

然后,测试用例直接跟使用一般的Service方法一模一样。

 

  1. @RunWith(SpringRunner.class)  
  2. @SpringBootTest(classes = Application.class)  
  3. public class CreatingThread08Test {  
  4.     @Autowired  
  5.     private CreatingThread08Service creatingThread08Service;  
  6.     @Test  
  7.     public void test() {  
  8.         creatingThread08Service.call();  
  9.         creatingThread08Service.call();  
  10.         creatingThread08Service.call();  
  11.         creatingThread08Service.call();  
  12.     }  
  13. } 

运行结果如下:

 

  1. task-3 is running  
  2. task-2 is running  
  3. task-1 is running  
  4. task-4 is running 

可以看到每次执行方法时使用的线程都不一样。

使用Spring异步方法的方式,可以说是相当地方便,适用于前后逻辑不相关联的适合用异步调用的一些方法,比如发送短信的功能。

总结

(1)继承Thread类并重写run()方法;

(2)实现Runnable接口;

(3)匿名内部类;

(4)实现Callabe接口;

(5)定时器(java.util.Timer);

(6)线程池;

(7)并行计算(Java8+);

(8)Spring异步方法;

彩蛋

上面介绍了那么多创建线程的方式,其实本质上就两种,一种是继承Thread类并重写其run()方法,一种是实现Runnable接口的run()方法,那么它们之间到底有什么联系呢?

请看下面的例子,同时继承Thread并实现Runnable接口,应该输出什么呢?

 

  1. public class CreatingThread09 {  
  2.     public static void main(String[] args) {  
  3.         new Thread(()-> {  
  4.             System.out.println("Runnable: " + Thread.currentThread().getName());  
  5.         }) {  
  6.             @Override  
  7.             public void run() {  
  8.                 System.out.println("Thread: " + getName());  
  9.             }  
  10.         }.start();  
  11.     }  
  12. } 

说到这里,我们有必要看一下Thread类的源码:

 

  1. public class Thread implements Runnable {  
  2.     // Thread维护了一个Runnable的实例  
  3.     private Runnable target;     
  4.     public Thread() { 
  5.          init(null, null, "Thread-" + nextThreadNum(), 0);  
  6.     }    
  7.     public Thread(Runnable target) {  
  8.         init(null, target, "Thread-" + nextThreadNum(), 0);  
  9.     }    
  10.     private void init(ThreadGroup g, Runnable target, String name,  
  11.                       long stackSize, AccessControlContext acc,  
  12.                       boolean inheritThreadLocals) {  
  13.         // ...  
  14.         // 构造方法传进来的Runnable会赋值给target  
  15.         this.target = target;  
  16.         // ...  
  17.     }    
  18.     @Override  
  19.     public void run() {  
  20.         // Thread默认的run()方法,如果target不为空,会执行target的run()方法  
  21.         if (target != null) {  
  22.             target.run();  
  23.         }  
  24.     }  
  25. } 

看到这里是不是豁然开朗呢?既然上面的例子同时继承Thread并实现了Runnable接口,根据源码,实际上相当于重写了Thread的run()方法,在Thread的run()方法时实际上跟target都没有关系了。

所以,上面的例子输出结果为Thread: Thread-0,只输出重写Thread的run()方法中的内容。

 

 

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
如何更省钱? 近期特价热门硒鼓... 如今激光打印设备已经成为商务或企业的绝对主力办公设备,但采购者往往忽视了激光打印设备所用的耗材,相对...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...