资讯专栏INFORMATION COLUMN

java 多线程

sutaking / 2356人阅读

摘要:的多线程有好几种,可以继承,也可以实现接口,还可以实现接口继承,自己实现方法,就可以定一个线程类,调用就可以在一个新的线程里面调用方法,如果需要等待线程结束,可以调用方法和差不多,只不过不直接继承,而是实现接口只有一个方法,使用上面用这个去

java 的多线程有好几种,可以继承 Thread,也可以实现 Runnable 接口,还可以实现 Callable 接口

Thread

</>复制代码

  1. class MyThread extends Thread {
  2. private String name;
  3. public MyThread(String name) {
  4. this.name = name;
  5. }
  6. @Override
  7. public void run() {
  8. for (int i = 0; i < 5; i++) {
  9. try {
  10. Thread.sleep(100L);
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. System.out.printf("%s is running %d
  15. ", name, i);
  16. }
  17. }
  18. }
  19. {
  20. Thread t1 = new MyThread("t1");
  21. Thread t2 = new MyThread("t2");
  22. t1.start();
  23. t2.start();
  24. try {
  25. t1.join();
  26. t2.join();
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }

继承 Thread,自己实现 run 方法,就可以定一个线程类,调用 start 就可以在一个新的线程里面调用 run 方法,如果需要等待线程结束,可以调用 join 方法

Runnable

</>复制代码

  1. class MyRunnable implements Runnable {
  2. private String name;
  3. public MyRunnable(String name) {
  4. this.name = name;
  5. }
  6. @Override
  7. public void run() {
  8. for (int i = 0; i < 5; i++) {
  9. try {
  10. Thread.sleep(100L);
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. System.out.printf("%s is running %d
  15. ", name, i);
  16. }
  17. }
  18. }
  19. {
  20. Thread r1 = new Thread(new MyRunnable("r1"));
  21. Thread r2 = new Thread(new MyRunnable("r2"));
  22. r1.start();
  23. r2.start();
  24. try {
  25. r1.join();
  26. r2.join();
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }

和 Thread 差不多,只不过不直接继承 Thread,而是实现 Runnable 接口(Runable 只有一个 run 方法),使用上面用这个 Runnable 去构造一个 Thread,这种方式相对直接继承 Thread 的方式要更加灵活,因为 java 是单继承,如果继承了 Thread 就不能再继承别的类

事实上,建议永远不要直接继承 Thread 类,因为从语义上来讲,Thread 也应该也只是方法运行的方式,你的类应该是可以在这种方式下运行,而不是一种 Thread 对象,从这个角度讲,Runnable 提供了更好的语义,用一个 Thread 对象去运行一个 Runable

Callable

</>复制代码

  1. class MyCallable implements Callable {
  2. private Random random;
  3. public MyCallable() {
  4. this.random = new Random();
  5. }
  6. @Override
  7. public Integer call() throws Exception {
  8. Thread.sleep(100L);
  9. return this.random.nextInt();
  10. }
  11. }
  12. {
  13. FutureTask future1 = new FutureTask<>(new MyCallable());
  14. FutureTask future2 = new FutureTask<>(new MyCallable());
  15. new Thread(future1).start();
  16. new Thread(future2).start();
  17. try {
  18. System.out.println(future1.get(50, TimeUnit.MILLISECONDS));
  19. } catch (TimeoutException e) {
  20. System.out.println("future1 timeout");
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. try {
  25. System.out.println(future2.get());
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }

Callable 接口也只有一个方法 call,和 Runnable 不同的是 Callable 允许有返回值,而这个返回值可以通过 FutureTask.get 获取,还可以设置任务运行的超时时间,超时后会抛出一个异常

ThreadPool

</>复制代码

  1. class MyCallable implements Callable {
  2. private Random random;
  3. public MyCallable() {
  4. this.random = new Random();
  5. }
  6. @Override
  7. public Integer call() throws Exception {
  8. Thread.sleep(100L);
  9. return this.random.nextInt();
  10. }
  11. }
  12. {
  13. ExecutorService es = Executors.newFixedThreadPool(5);
  14. Future future1 = es.submit(new MyCallable());
  15. Future future2 = es.submit(new MyCallable());
  16. try {
  17. System.out.println(future1.get(50, TimeUnit.MILLISECONDS));
  18. } catch (TimeoutException e) {
  19. System.out.println("future1 timeout");
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. try {
  24. System.out.println(future2.get());
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. es.shutdown();
  29. }

java 里面线程的创建和销毁成本比较大,所以一般会需要放到线程池里面跑,java 的基础设施就是好,这些在标准库里面都有实现,使用上面也很简单,直接 new 出一个线程池就好了,然后就可以往里面 submit Callable 对象,线程池也有很多种,上面用到的 newFixedThreadPool 是固定线程数的线程池,下面用到的 newCachedThreadPool 在线程不够用的时候会创建新线程,同时也会不断复用之前创建的线程

</>复制代码

  1. {
  2. ExecutorService es = Executors.newCachedThreadPool();
  3. CompletionService cs = new ExecutorCompletionService<>(es);
  4. cs.submit(new MyCallable());
  5. cs.submit(new MyCallable());
  6. cs.submit(new MyCallable());
  7. cs.submit(new MyCallable());
  8. try {
  9. System.out.println(cs.take().get());
  10. System.out.println(cs.take().get());
  11. System.out.println(cs.take().get());
  12. System.out.println(cs.take().get());
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. es.shutdown();
  17. }

典型的生成者消费者模型里面,我们需要把生产的结果放到一个队列里面,而消费者从这个队列里面不断地去消费,ExecutorCompletionService 就相当于这个队列,MyCallable 的结果会写入到缓存里面,使用 cs.take().get() 从里面取出结果

总结

线程的创建,销毁,切换在 java 里面都是耗性能的操作,如果有需求要大量地创建线程,尽量使用线程池去复用线程

参考链接

测试代码链接:https://github.com/hatlonely/...

“implements Runnable” vs. “extends Thread” :https://stackoverflow.com/que...

</>复制代码

  1. 转载请注明出处
    本文链接:http://hatlonely.com/2018/03/...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68835.html

相关文章

  • Java线程学习(一)Java线程入门

    摘要:最近听很多面试的小伙伴说,网上往往是一篇一篇的多线程的文章,除了书籍没有什么学习多线程的一系列文章。将此线程标记为线程或用户线程。 最近听很多面试的小伙伴说,网上往往是一篇一篇的Java多线程的文章,除了书籍没有什么学习多线程的一系列文章。但是仅仅凭借一两篇文章很难对多线程有系统的学习,而且面试的时候多线程这方面的知识往往也是考察的重点,所以考虑之下决定写一系列关于Java多线程的文章...

    Donne 评论0 收藏0
  • Java线程专题一:并发所面临的问题

    摘要:但是并不是什么多线程就可以随便用,有的时候多线程反而会造成系统的负担,而且多线程还会造成其他的数据问题,下面就来介绍一下多线程面临的问题。下面这张图是多线程运行时候的情况,我们发现上下文切换的次数暴增。 并发的概念: 在Java中是支持多线程的,多线程在有的时候可以大提高程序的速度,比如你的程序中有两个完全不同的功能操作,你可以让两个不同的线程去各自执行这两个操作,互不影响,不需要执行...

    madthumb 评论0 收藏0
  • Java线程可以分组,还能这样玩!

    摘要:如图所示,带有的所有线程构造方法都可以定义线程组的。线程组还能统一设置组内所有线程的最高优先级,线程单独设置的优先级不会高于线程组设置的最大优先级。 前面的文章,栈长和大家分享过多线程创建的3种方式《实现 Java 多线程的 3 种方式》。 但如果线程很多的情况下,你知道如何对它们进行分组吗? 和 Dubbo 的服务分组一样,Java 可以对相同性质的线程进行分组。 来看下线程类 Th...

    biaoxiaoduan 评论0 收藏0
  • JAVA 线程和并发基础

    摘要:线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。在的线程中并没有可供任何对象使用的锁和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻译:并发编程网 - 郑旭东 校对:方腾飞 多...

    vboy1010 评论0 收藏0
  • Java线程学习(七)并发编程中一些问题

    摘要:相比与其他操作系统包括其他类系统有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。因为多线程竞争锁时会引起上下文切换。减少线程的使用。很多编程语言中都有协程。所以如何避免死锁的产生,在我们使用并发编程时至关重要。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)syn...

    dingding199389 评论0 收藏0
  • 学习Java线程的一些总结

    摘要:多线程环境下的一些问题安全性问题在没有正确同步的情况下,多线程环境下程序可能得出错误的结果。一些相关概念竞争条件多线程的环境下,程序执行的结果取决于线程交替执行的方式。而线程的交替操作顺序是不可预测的,如此程序执行的结果也是不可预测的。 入口 Java多线程的应用复杂性之如jvm有限的几个内存方面的操作和规范,就像无数纷繁复杂的应用逻辑建立在有限的指令集上。 如何写出线程安全的程序,有...

    coolpail 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<