资讯专栏INFORMATION COLUMN

java 多线程

sutaking / 2240人阅读

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

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

Thread
class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(100L);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.printf("%s is running %d
", name, i);
        }
    }
}

{
    Thread t1 = new MyThread("t1");
    Thread t2 = new MyThread("t2");

    t1.start();
    t2.start();
    try {
        t1.join();
        t2.join();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

Runnable
class MyRunnable implements Runnable {
    private String name;

    public MyRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(100L);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.printf("%s is running %d
", name, i);
        }
    }
}

{
    Thread r1 = new Thread(new MyRunnable("r1"));
    Thread r2 = new Thread(new MyRunnable("r2"));

    r1.start();
    r2.start();
    try {
        r1.join();
        r2.join();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

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

Callable
class MyCallable implements Callable {
    private Random random;

    public MyCallable() {
        this.random = new Random();
    }

    @Override
    public Integer call() throws Exception {
        Thread.sleep(100L);
        return this.random.nextInt();
    }
}

{
    FutureTask future1 = new FutureTask<>(new MyCallable());
    FutureTask future2 = new FutureTask<>(new MyCallable());
    new Thread(future1).start();
    new Thread(future2).start();

    try {
        System.out.println(future1.get(50, TimeUnit.MILLISECONDS));
    } catch (TimeoutException e) {
        System.out.println("future1 timeout");
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        System.out.println(future2.get());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

ThreadPool
class MyCallable implements Callable {
    private Random random;

    public MyCallable() {
        this.random = new Random();
    }

    @Override
    public Integer call() throws Exception {
        Thread.sleep(100L);
        return this.random.nextInt();
    }
}

{
    ExecutorService es = Executors.newFixedThreadPool(5);
    Future future1 = es.submit(new MyCallable());
    Future future2 = es.submit(new MyCallable());

    try {
        System.out.println(future1.get(50, TimeUnit.MILLISECONDS));
    } catch (TimeoutException e) {
        System.out.println("future1 timeout");
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        System.out.println(future2.get());
    } catch (Exception e) {
        e.printStackTrace();
    }

    es.shutdown();
}

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

{
    ExecutorService es = Executors.newCachedThreadPool();
    CompletionService cs = new ExecutorCompletionService<>(es);
    cs.submit(new MyCallable());
    cs.submit(new MyCallable());
    cs.submit(new MyCallable());
    cs.submit(new MyCallable());

    try {
        System.out.println(cs.take().get());
        System.out.println(cs.take().get());
        System.out.println(cs.take().get());
        System.out.println(cs.take().get());
    } catch (Exception e) {
        e.printStackTrace();
    }

    es.shutdown();
}

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

总结

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

参考链接

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

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

转载请注明出处 
本文链接: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元查看
<