Java多线程——创建线程的三种方式
在Java中,使用多线程编程时,创建一个线程类主要有三种方式:
(1)继承Thread类的方式创建线程类;
(2)通过实现Runnable接口创建线程类;
(3)通过Callable和Future来创建线程类。
① 定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务,因此把run方法称为执行体;
②创建Thread子类的实例,即创建线程对象;
③调用线程对象的start()方法来启动该线程;该线程会执行run()方法里面的内容,执行完毕即退出。
public class CreateThreadbyExtendsThread {
public static void main(String[] args) {
for(int i = 0;i< 50;i++)
{
//Thread.currentThread()方法返回当前正在执行的线程对象。GetName()方法返回调用该方法的线程的名字。
System.out.println(Thread.currentThread().getName()+" : "+i);
if(i==5)
{
new myThread().start();
new myThread().start();
}
}
}
}
class myThread extends Thread{
int i=0;
@Override
public void run(){
for(;i<15;i++){
System.out.println(getName()+" "+i);
}
}
}
结果示例:
① 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的执行体;
② 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
③ 调用线程对象的start()方法来启动该线程。
public class CreateThreadByImpRunnable {
public static void main(String[] args) {
for(int i = 0;i < 20;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==5)
{
myRunnableThread rtt = new myRunnableThread();
new Thread(rtt,"新线程1").start();
new Thread(rtt,"新线程2").start();
}
}
}
}
class myRunnableThread implements Runnable{
private int i;
@Override
public void run() {
for(i = 0;i <20;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
结果示例:
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体(就如上述的run()方法一样),需要关注的是:该方法时有返回值的,源码如下:
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该Future对象封装了该Callable对象的call()方法的返回值。FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了Future和Runnable接口;
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程;
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public class CreateThreadByCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallableThread myCallableThread = new MyCallableThread();
FutureTask<Integer> ft = new FutureTask<>(myCallableThread);
for(int i=0;i<15;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
if(i==5){
new Thread(ft,"有返回值的线程").start();
}
}
//获取线程的返回值
System.out.println("子线程的返回值:"+ft.get());
}
}
class MyCallableThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int i=0;
for(;i<5;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
结果输出示例:
(1)优点:
① 线程类知识实现了Runnable接口或Callable接口,还可以继承其他类;
② 在这种方式下,多个线程可以共享同一个target对象,所有非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现面向对象的思想。
(2)缺点:
① 编程稍复杂;
②如果要访问当前线程,则必须使用Thread.currentThread()的方法。
(1)优点
① 编写简单;
② 如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
(2)缺点
① 线程类已经继承了Thread类,不能再继承其他父类了。
(1)重写的方法(方法体)不同:Callable重写call()方法;Runnable重写run()方法;
(2)Callablle的任务执行后可返回值;在Runnable的任务是没有返回值的;
(3)Callable的call()方法可以抛出异常;Runnable的run()方法不可以;
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可以获取执行结果。
本文源代码:
本文参考:
声明:本文部分内容整理来源于网络,仅做个人学习使用!侵删~
因篇幅问题不能全部显示,请点此查看更多更全内容