本文主要详细介绍了在Java中创建线程的五种常用方法。文中的样例代码讲解的很详细,对我们学习很有帮助。有兴趣的可以跟着边肖学。
目录
题目描述解题思路代码详解第一类继承thread类创建线程,第二类实现Runnable接口创建线程,第三类实现Callable接口,第四种通过FutureTask包装器创建线程Thread的方法是使用ExecutorService、Callable(或Runnable)和Future实现返回结果的线程。第五种方式是使用ComletetableFuture类创建异步线程,并且是返回结果的线程。
题目描述
创建Java线程的几种方法
用Java线程类来表示线程,所有的线程对象都必须是线程类或其子类的实例。Java可以通过以下五种方式创建线程
继承Thread类以创建线程;实现Runnable接口来创建线程;实现可调用接口,通过FutureTask包装器创建线程Thread;使用ExecutorService、Callable(或Runnable)和Future实现从返回结果的线程。使用CompletableFuture类创建一个异步线程,它就是返回结果的线程。JDK8支持的新功能
实现:使用这5种方法来创建线程,并体验它们的美丽。
解题思路
继承Thread类以创建线程
Thread类本质上是Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法是通过Thread类的start()实例方法。start()方法是一个本机方法,它将启动一个新线程并执行run()方法。这样实现多线程非常简单。您可以启动一个新线程并执行您自己定义的run()方法,方法是通过您自己的类直接扩展线程并覆盖run()方法。
实现Runnable接口来创建线程。
如果你的类扩展了另一个类,你不能直接扩展线程。在这种情况下,您可以实现一个Runnable接口。
实现可调用接口,通过FutureTask包装器创建线程Thread。
实现一个可调用的接口(它是一个具有返回值的)
使用ExecutorService、Callable(或Runnable)和Future来实现从返回结果的线程。
Executors类,提供了一系列创建线程池的工厂方法,返回的线程池都实现了ExecutorService接口:
Executors类,提供了一系列创建线程池的工厂方法,返回的线程池都实现了ExecutorService接口:
//创建一个线程数量固定的线程池。
public static ExecutorService newFixedThreadPool(int nThreads);
//创建一个可缓存的线程池,调用execute会重用之前构造的线程(如果线程可用)。如果没有可用的现有线程,请创建一个新线程并将其添加到池中。终止并从缓存中删除60秒内未使用的线程。
公共静态ExecutorService newCachedThreadPool();
//创建单线程执行器。
public static ExecutorService newSingleThreadExecutor();
//创建一个支持定时、周期性任务执行的线程池,大多数情况下可以代替Timer类使用。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
ExecutoreService提供submit()方法,传递一个Callable或Runnable,并返回未来值。如果Executor后台线程池还没有完成Callable的计算,这就调用返回Future对象的get()方法,这个方法会一直阻塞,直到计算完成。
使用CompletableFuture类创建一个异步线程,它就是返回结果的线程。
Future模式的缺点
Future虽然可以满足获取异步执行结果的要求,但是它没有提供通知机制,我们无法知道Future什么时候完成。
要么使用阻塞,在future.get()处等待future返回的结果,然后又变成同步操作。要么用isDone()轮询确定未来是否完成,这会消耗CPU资源。
CompletableFuture 介绍
JDK1.8是新增加的实现类CompletableFuture,实现了两个接口:Future,CompletionStage。
CompletableFuture中异步任务执行的四种静态方法:
public static U CompletableFutureU supply sync(供应商供应商){
返回asyncsupplistage(asyncPool,供应商);
}
公共静态U CompletableFutureU供应同步(供应商U供应商,执行者执行者){
返回asyncsupplistage(屏幕执行器(执行者),供应商);
}
公共静态CompletableFutureVoid异步运行(Runnable Runnable){
返回asyncRunStage(asyncPool,runnable);
}
公共静态CompletableFutureVoid异步运行(Runnable Runnable,Executor executor) {
返回asyncRunStage(screenExecutor(执行者),可运行);
}
其中供应同步用于有返回值的任务,运行异步则用于没有返回值的任务遗嘱执行人参数可以手动指定线程池,否则默认ForkJoinPool.commonPool()系统级公共线程池
代码详解
第一种 继承Thread类创建线程
包cn。朱秀旭。日常;
导入Java。util。并发。countdownlatch
/**
*描述:继承线类创建线程
*
* @作者小王同学
* @版本1.0
*/
公共类线程演示1扩展线程{
计数下降
公共线程演示1(CountDownLatch CountDownLatch){
这个。countDownLatch=countDownLatch
}
@覆盖
公共无效运行(){
尝试{
线程。睡眠(2000年);
系统。出去。println(线程。当前线程().getName()':我的线程');
} catch (InterruptedException e) {
e。printstacktrace();
}最后{
countdownlatch。倒计时();
}
}
公共静态void main(String[] args) {
//第一种:使用延伸螺纹方式
CountDownLatch CountDownLatch 1=new CountDownLatch(2);
for(int I=0;I 2;i ) {
线程演示1 mythread 1=新线程演示1(countdownlatch 1);
流言1。start();
}
尝试{
countdownlatch 1。await();
'线程完成.');
} catch (InterruptedException e) {
e。printstacktrace();
}
}
}
第二种:实现Runnable接口创建线程
包cn。朱秀旭。日常;
导入Java。util。并发。countdownlatch
/**
*描述:实现可追捕的接口创建线程
*
* @作者小王同学
* @版本1.0
*/
公共类线程演示2实现可运行{
计数下降
公共线程演示2(CountDownLatch CountDownLatch){
这个。countDownLatch=countDownLatch
}
@覆盖
公共无效运行(){
尝试{
线程。睡眠(2000年);
系统。出去。println(线程。当前线程().getName()':my runnable ');
} catch (InterruptedException e) {
e。printstacktrace();
}最后{
countdownlatch。倒计时();
}
}
公共静态void main(String[] args) {
//第二种:使用实现可运行方式
CountDownLatch CountDownLatch 2=new CountDownLatch(2);
线程演示2 my runnable=新线程演示2(countdownlatch 2);
for(int I=0;I 2;i ) {
新线程(我无法运行).start();
}
尝试{
countdownlatch 2。await();
System.out.println('可运行完成.');
} catch (InterruptedException e) {
e。printstacktrace();
}
}
}
第三种:实现Callable接口,通过FutureTask包装器来创建Thread线程
计算1~100的叠加
包cn。朱秀旭。日常;
导入Java。util。并发。可赎回;
导入Java。util。并发。执行异常;
导入Java。util。并发。未来任务;
/**
*描述:实现请求即付的接口,通过未来任务包装器来创建线线程
* 跟可追捕的比,不同点在于它是一个具有返回值的,且会抛出异常
* //用未来任务接收结果
*
* @作者小王同学
* @版本1.0
*/
公共类线程演示3实现CallableInteger {
公共静态void main(String[] args) {
thread demo 3 thread demo 03=new thread demo 3();
//1、用未来任务接收结果
FutureTaskInteger未来任务=新的未来任务(thread demo 03);
新线程(未来任务).start();
//2、接收线程运算后的结果
尝试{
//未来任务。get();这个是堵塞性的等待
整数和=未来任务。get();
系统。出去。println(' sum=' sum);
系统。出去。println('-');
} catch (InterruptedException e) {
e。printstacktrace();
} catch (ExecutionException e) {
e。printstacktrace();
}
}
@覆盖
公共整数调用()引发异常{
int sum=0;
for(int I=0;i 101i ) {
sum=I;
}
返回总和;
}
}
第四种:使用ExecutorService、Callable(或者Runnable)、Future实现返回结果的线程
包cn。朱秀旭。日常;
导入Java。util。ArrayList
导入Java。util。迭代器;
导入Java。util。列表;
导入Java。util。并发。可赎回;
导入Java。util。并发。countdownlatch
导入Java。util。并发。执行异常;
导入Java。util。并发。执行服务;
导入Java。util。并发。遗嘱执行人;
导入Java。util。并发。未来;
/**
*描述:使用执行服务、可调用(或者可运行的)、未来实现由返回结果的线程
*
* @作者小徐竹
* @版本1.0
*/
公共类线程演示4 {
静态类MyCallable实现CallableInteger {
private CountDownLatch CountDownLatch;
public my callable(CountDownLatch CountDownLatch){
这个。countDownLatch=countDownLatch
}
公共整数调用(){
int sum=0;
尝试{
for(int I=0;i=100i ) {
sum=I;
}
System.out.println('线程执行结果:' sum);
}最后{
countdownlatch。倒计时();
}
返回总和;
}
}
公共静态void main(String[] args)引发ExecutionException、InterruptedException {
//第四种:使用使用线程池方式
//接受返回参数
列出未来结果项2=new ArrayList future();
//給线程池初始化5個线程
执行者服务=执行者。newfixedthreadpool(5);
CountDownLatch CountDownLatch 4=new CountDownLatch(10);
for(int I=0;i 10i ) {
my callable my callable=new my callable(countdownlatch 4);
未来结果=executorservice。提交(我的可调用);
结果项2.add(结果);
}
//等待线程池中分配的任务完成后才关闭(关闭之后不允许有新的线程加入,但是它并不会等待线程结束),
//而执行服务。立即关闭();是立即关闭不管是否线程池中是否有其他未完成的线程。
执行服务。关闭();
尝试{
countdownlatch 4。await();
迭代器未来迭代器=结果项2。迭代器();
系统。出去。println('-');
while (iterator.hasNext()) {
尝试{
System.out.println('线程返回结果:' iterator.next().get());
} catch (ExecutionException e) {
e。printstacktrace();
}
}
System.out.println('可调用完成.');
} catch (InterruptedException e) {
e。printstacktrace();
}
}
}
第五种:使用ComletetableFuture类创建异步线程,且是据有返回结果的线程
包cn。朱秀旭。日常;
导入Java。util。并发。completablefuture
导入Java。util。并发。执行异常;
导入Java。util。并发。执行服务;
导入Java。util。并发。遗嘱执行人;
导入Java。util。并发。时间单位;
导入org。朱尼特。测试;
/**
*描述:使用可完成的未来类创建异步线程,且是据有返回结果的线程。
*
* @作者小徐竹
* @版本1.0
*/
公共类ThreadDemo5 {
/**
* A任务B任务完成后,才执行C任务
* 返回值的处理
* @param
* @返回空的
**/
@测试
public void completablefuture 1(){
CompletableFutureString future 1=completablefuture。供应同步(()-{
尝试{
线程.睡眠(十);
} catch (InterruptedException e) {
e。printstacktrace();
}
System.out.println('未来1已完成!');
返回"未来一完成!";
});
CompletableFutureString future 2=completablefuture。供应同步(()-{
System.out.println('未来2已完成!');
返回"未来2完成!";
});
CompletableFutureVoid future 3=completablefuture。allof(未来1,未来2);
尝试{
未来3。get();
} catch (InterruptedException e) {
e。printstacktrace();
} catch (ExecutionException e) {
e。printstacktrace();
}
系统。出去。println('未来1:'未来1。isdone()'未来2:'未来2。isdone());
}
/**
* 在Java8中,CompletableFuture提供了非常强大的将来的的扩展功能,可以帮助我们简化异步编程的复杂性,
* 并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合可完成的未来的方法
*
* 注意:方法中有异步非同步(异步)一般表示另起一个线程,没有表示用当前线程
*/
@测试
公共void test01()引发异常{
执行者服务=执行者。newfixedthreadpool(5);
/**
*供应同步用于有返回值的任务,
*运行异步则用于没有返回值的任务
*执行者参数可以手动指定线程池,否则默认ForkJoinPool.commonPool()系统级公共线程池
*/
CompletableFutureString future=completablefuture。供应同步(()-{
尝试{
线程。睡眠(3000);
} catch (InterruptedException e) {
e。printstacktrace();
}
返回'小旭珠;
}、服务);
completablefuture void data=completablefuture。运行异步(()-system。出去。println('秀虚竹');
/**
* 计算结果完成回调
*/
future.whenComplete((x,y)- System.out.println('有延迟3秒:执行当前任务的线程继续执行:' x ',' y));//执行当前任务的线程继续执行
data.whenCompleteAsync((x,y)- System.out.println('交给线程池另起线程执行:' x ',' y));//交给线程池另起线程执行
未来。exceptive(Throwable:toString);
//系统。出去。println(未来。get());
/**
*然后应用,一个线程依赖另一个线程可以使用,出现异常不执行
*/
//第二个线程依赖第一个的结果
CompletableFutureInteger future 1=completablefuture。supply sync(()-5).然后应用(x-x);
/**
*手柄是执行任务完成时对结果的处理,第一个出现异常继续执行
*/
CompletableFutureInteger未来2=未来1。句柄异步((x,y)-x ^ 2);
系统。出去。println(未来2。get());//7
/**
*然后接受消费处理结果,不返回
*/
未来2。然后接受(系统。out:println);
/**
*然后运行不关心任务的处理结果。只要上面的任务执行完成,就开始执行
*/
未来2。therunasync(()-系统。出去。println('继续下一个任务'));
/**
*然后合并会把两个完成阶段的任务都执行完成后,两个任务的结果交给然后合并来处理
*/
CompletableFutureInteger未来3=未来1。然后合并(future 2,Integer:sum);
系统。出去。println(未来3。get());//5 7=12
/**
*然后接受两者:当两个完成阶段都执行完成后,把结果一块交给然后接受两者来进行消耗
*/
未来1。thenacceptbothasync(future 2,(x,y)- System.out.println(x ',' y));//5,7
/**
*应用任一
* 两个完成阶段,谁执行返回的结果快,我就用那个完成阶段的结果进行下一步的转化操作
*/
completablefutureininteger future 4=future 1 . apply tonor(future 2,x-x);
system . out . println(future 4 . get());//5
/**
*接受任一
*两个完成阶段。谁快速执行返回的结果,谁就将使用该CompletionStage的结果进行下一次消费操作。
*/
future 1 . accept要么(future2,system . out:println);
/**
*运行后
*两个CompletionStage,其中任何一个都将在完成时执行下一个操作(Runnable
*/
未来1。RunAfterIther (future,()-system.out.println('一个完了,我继续'));
/**
* runAfterBoth
*两个CompletionStage,只有在计算完成后才会执行下一个操作(Runnable)。
*/
未来1。RunAfterBoth (future,()-system.out.println('都做完了,我继续'));
/**
* thenCompose方法
* thenCompose方法允许您管道化多个CompletionStage。当第一个操作完成时,结果作为参数传递给第二个操作。
* apply是接受一个函数,thenCompose是接受一个未来的实例,更适合处理流操作。
*/
future 1 . then compose async(x-completablefuture . supply async(()-x 1))。然后compose async(x-completablefuture . supply async(()-x ^ 2))。然后compose(x-complextablefuture . run async(()-system . out . println(' stream operation result:' x))));
时间单位。秒.睡眠(5);//主线程休眠,等待其他线程执行
}
}
以上是理解Java线程创建的五种方式的细节。关于Java线程创建的更多信息,请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。