起航学习网

- 让每个人都能学到最前沿新知识、新技能!
起航学习网
当前位置: 起航学习网 > 短期培训 > 编程语言 > Java线程创建的方法有哪些

Java线程创建的方法有哪些

时间:2019-10-10 13:54:32来源:编程网 作者:IT培训网 已有: 名学员访问该课程

  快捷搜索:java线程(8)

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

死磕 Java线程系列之创建线程的8种方式

Java线程创建的方法有哪些_www.epx365.cn

简介

创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有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.     }  

继承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.     }  

实现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.     }  

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

实现Callabe接口


  1. public class CreatingThread04 implements Callable<long> {  
  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<long> task = new FutureTask&lt;&gt;(new CreatingThread04());  
  10.         new Thread(task).start();  
  11.         System.out.println("等待完成任务");  
  12.         Long result = task.get();  
  13.         System.out.println("任务结果:" + result);  
  14.     }  

实现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.     }  

使用定时器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 &lt; 100; i++) {  
  5.             threadPool.execute(()-&gt; System.out.println(Thread.currentThread().getName() + " is running"));  
  6.         }  
  7.     }  

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

并行计算(Java8+)


  1. public class CreatingThread07 {  
  2.     public static void main(String[] args) {  
  3.         List<integer> 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.     }  

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

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.     }  

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


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

然后,测试用例直接跟使用一般的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.     }  

运行结果如下:


  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(()-&gt; {  
  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.     }  

说到这里,我们有必要看一下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.     }  

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

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

来源地址:http://www.epx365.cn/peixun/software/201956752.html

来源标题:Java线程创建的方法有哪些



免责声明:本站文章均由入驻起航学习网的会员所发或者网络转载,所述观点仅代表作者本人,不代表起航学习网立场。如有侵权或者其他问题,请联系举报,必删。侵权投诉

(责任编辑:IT培训网)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
培训学校
IT培训网 访问该机构站点 报名留言 加为好友 用户等级:注册会员 用户级别:10 机构名称:IT培训网 联 系 人:罗老师 联系电话: 联系手机:13783581536 在线客服:起航学习网客服 在 线 QQ:起航学习网客服 电子邮件:3158895217@qq.com 网站域名:http://www.cnitedu.cn 注册时间:2016-07-18 11:07 最后登录:2019-10-10 13:10