摘要:的多线程有好几种,可以继承,也可以实现接口,还可以实现接口继承,自己实现方法,就可以定一个线程类,调用就可以在一个新的线程里面调用方法,如果需要等待线程结束,可以调用方法和差不多,只不过不直接继承,而是实现接口只有一个方法,使用上面用这个去
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中是支持多线程的,多线程在有的时候可以大提高程序的速度,比如你的程序中有两个完全不同的功能操作,你可以让两个不同的线程去各自执行这两个操作,互不影响,不需要执行...
摘要:如图所示,带有的所有线程构造方法都可以定义线程组的。线程组还能统一设置组内所有线程的最高优先级,线程单独设置的优先级不会高于线程组设置的最大优先级。 前面的文章,栈长和大家分享过多线程创建的3种方式《实现 Java 多线程的 3 种方式》。 但如果线程很多的情况下,你知道如何对它们进行分组吗? 和 Dubbo 的服务分组一样,Java 可以对相同性质的线程进行分组。 来看下线程类 Th...
摘要:线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。在的线程中并没有可供任何对象使用的锁和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻译:并发编程网 - 郑旭东 校对:方腾飞 多...
摘要:相比与其他操作系统包括其他类系统有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。因为多线程竞争锁时会引起上下文切换。减少线程的使用。很多编程语言中都有协程。所以如何避免死锁的产生,在我们使用并发编程时至关重要。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)syn...
摘要:多线程环境下的一些问题安全性问题在没有正确同步的情况下,多线程环境下程序可能得出错误的结果。一些相关概念竞争条件多线程的环境下,程序执行的结果取决于线程交替执行的方式。而线程的交替操作顺序是不可预测的,如此程序执行的结果也是不可预测的。 入口 Java多线程的应用复杂性之如jvm有限的几个内存方面的操作和规范,就像无数纷繁复杂的应用逻辑建立在有限的指令集上。 如何写出线程安全的程序,有...
阅读 3657·2021-11-17 17:01
阅读 4016·2021-11-08 13:12
阅读 2621·2021-10-08 10:04
阅读 801·2021-09-29 09:35
阅读 1529·2021-09-26 10:12
阅读 2258·2021-09-07 09:58
阅读 2098·2019-08-30 15:55
阅读 2212·2019-08-30 13:14