Java使用线程类来表示线程,所有线程对象必须是线程类或其子类的实例Java可以通过四种方式创建线程,如下所示:
1)继承线程类创建线程;
2)可运行接口创建线程的实现;
3)实现了可调用接口,通过FutureTask包装器创建线程;
4)使用ExecutorService、可调用、未来来实现具有返回结果的线程
,其中前两个线程在执行后没有返回值,后两个线程有返回值
继承线程类创建线程
通过继承线程类创建和启动多线程的一般步骤如下:
1]定义线程类的子类并重写该类的运行方法。方法体是线程需要完成的任务,run方法也称为线程执行器;
2]创建线程子类的实例,即创建线程对象;
3]启动线程,即调用线程的启动方法
代码实例
公共类MyThread extend thread {//继承线程类
公共void run {
//重写运行方法
}
}
公共类Main {
公共静态void Main(String args){
new MyThread start;//创建和启动线程
}
)
可运行接口的实现创建线程
通过实现可运行接口创建和启动线程的一般步骤如下:
1]定义可运行接口的实现类,重写运行方法,该方法与线程中的运行方法相同,作为线程的执行体;
2]创建一个Runnable实现类的实例,并使用这个实例作为线程的目标来创建一个线程对象,它是真正的线程对象。
3]第三步仍然是通过调用线程对象的start方法来启动线程。
代码示例:
公共类我的线程实现Runnable {//实现Runnable接口
公共void run {
//重写运行方法
}
}
public class main {
public static void main(string GS){
//创建并启动线程
螺纹螺纹=新螺纹(螺纹);
线程. start;
//或newthread (newmythread)。
}
}
使用可调用和未来创建线程。
不同于Runnable接口。可调用接口提供了一个调用方法作为线程执行器。调用方法比运行方法更强大:
调用方法可以有返回值;
调用方法可以声明抛出异常
Java5提供了Future接口来表示可调用接口中调用方法的返回值,并为Future接口提供了一个实现类Futuretask。这个实现类实现了未来接口和可运行接口,因此它可以用作线程类的目标在未来接口中定义了几种常用的方法来控制其相关的可调用任务
布尔取消(布尔五月中断):视图取消将来关联的可调用任务;
get:返回Callable中调用方法的返回值。调用此方法将导致程序阻塞,并且直到子线程结束才会获得返回值。
get (longtimeout,timeunitUnit):返回Callable中调用方法的返回值,最多阻止超时,在指定时间后不返回引发TimeoutException
布尔isDone:如果可调用任务已完成,则返回真;
布尔型:如果在可调用任务正常完成之前取消,则返回真在
引入相关概念后,创建和启动具有返回值的线程的步骤如下:
1]创建可调用接口实现类,实现调用方法,然后创建实现类的实例(可以直接使用Lambda表达式从Java8开始创建可调用对象);
2]使用FutureTask类包装可调用对象,它封装了可调用对象的调用方法的返回值;
3]使用FutureTask对象作为线程对象的目标来创建和启动线程(因为FutureTask实现了可运行接口);
4]在子线程完成执行后,调用FutureTask对象的get方法来获取返回值。
代码示例:
public class main {
public static void main(string GIS){
mythread 3rd = new mythread 3;
//使用Lambda表达式创建可调用对象
//使用FutureTask类包装可调用对象
FutureTask =新FutureTask (
(可调用)-{
RETUR5;
}
);
新线程(任务,带返回值的线程)。开始;
//实质上,线程
try {
system . out . println(子线程的返回值:+future.get)是用Callable对象创建和启动的。在子线程执行结束之前,
//get方法将阻止并且不会返回
} catch(异常e){
ex . printstacktrace;
}
)
)
使用ExecutorService、Callable和Future来实现返回结果的线程-
ExecutorService、Callable和Future实际上是Executor框架的一部分返回结果的线程是JDK1.5中引入的一个新特性。有了这个特性,您不必费很大的劲就能得到返回值。此外,如果由它自己实施,它可能充满漏洞。
可返回任务必须实现可调用接口同样,不返回值的任务必须实现可运行接口
执行可调用任务后,可以获得一个未来对象。对对象调用get可以获得可调用任务返回的对象。
注意:get方法被阻塞,也就是说,线程不返回结果,get方法将一直等待。
与线程池接口ExecutorService相结合,可以实现以图例形式返回结果的多线程。
提供了一个完整的多线程测试示例,返回的结果已经在JDK1.5下得到验证,可以直接使用。代码如下:
import Java . util . concurrent . *;
导入Java . util . date;
导入Java . util . list;
import Java . util . ArrayList;
/**
*线程,返回值
*/
@ suppress warnings(未选中)
public class test {
public static void main(string GS)引发executionexception,
中断异常{
system . out . println(-程序开始运行-);
日期1 =新日期;
int TaskSize = 5;
//创建线程池
执行服务池=执行程序。新固定线程池(Taskssize);
//创建多个任务,返回值
列表=新数组列表;
for(int I = 0;I任务大小;i++) {
Callable c =新的MyCallable(I+);
//执行任务并获得未来对象
未来f =池。
//system . out . println(+f . get . ToString);
list . add(f);
}
//关闭线程池
。关闭;
//获取所有并发任务
的运行结果(未来F:列表){
//从未来对象获取任务的返回值,并将其输出到控制台
系统。out . println(+f . get . to string);
}
日期日期2 =新日期;
system . out . println(-程序结束运行,程序运行时间[
+(date 2 . gettime-date 1 . gettime)+毫秒));
}
}
class MyCallable实现可调用的{
私有字符串taskNum
毫秒可调用(字符串任务数){
this.taskNum =任务数;
}
public object call引发异常{
system . out . println(+task num+任务启动);
日期时间p1 =新日期;
线程睡眠(1000);
日期2 =新日期;
长时间=日期时间2.getTime -日期时间1 . GetTime;out . println(+task num+任务终止);
返回TaskNum+任务返回运行结果,当前任务时间为[+时间+毫秒];
}
)
代码描述:
上述代码中的Executors类提供了一系列创建线程池的工厂方法。返回的线程池都实现了ExecutorService接口
public static executorservice newfixedthreadpool(intnthreads)
创建一个具有固定线程数的线程池
public static executorservice new cache thread pool
创建一个可缓存的线程池,调用execute将重用以前构建的线程(如果可用)如果没有可用的现有线程,请创建一个新线程并将其添加到池中终止并从缓存中删除60秒内未使用的线程。
public static Executorservice newsingletheadeExecutor
创建一个单线程执行器
公共工作站调度执行服务新闻调度读取池(INT COREPOLOPSIZE)
创建支持定时和定期任务执行的线程池,在大多数情况下可用于替换计时器类
ExecutoreService提供提交方法,将可调用或可运行的返回传递给未来如果执行器后台线程池尚未完成可调用的计算,则此调用返回Future对象的get方法,并将阻塞直到计算完成
的前三个线程创建方法在实现Runnable和Callable接口方面与
的基本相同,但是后者在执行Callable方法时有返回值,而后者在执行线程执行器的运行方法时没有返回值。因此,这两种方法和继承线程类的方法的区别如下:
1,线程只实现Runnable或callable接口,它们调用也继承其他类;
2。这样,多个线程可以共享一个目标对象,这非常适合同一资源的多线程处理。
3,但是编程有点复杂,如果需要访问当前线程,必须调用Thread.currentThread方法;
4,继承线程类的线程类不能继承其他父类(Java单一继承决策)
注意:通常建议创建多线程
生命周期
Java语言使用线程类及其子类的对象来表示线程。在一个完整的生命周期中,它通常经历以下五种状态:
1,新建:当线程类或其子类的对象被声明和创建时,新创建的线程对象处于新创建的状态
2,准备好:在新创建的线程启动后,它将进入线程队列等待CPU时间片。此时,它已经具备运行条件
3。运行:当就绪线程被调度并获得处理器资源时,它将进入运行状态。run方法定义了线程的操作和功能
4,阻塞:在某些特殊情况下,当被人工挂起或执行输入和输出操作时,CPU被释放并暂时从其自身执行中挂起,进入阻塞状态
5,dead:线程已经完成其所有工作或线程被强制挂起