关于java的Runableh和Clallable的笔记

  我们知道,通常创建线程的方式有继承Thread类,实现Runnable接口并重写Run()方法的实现类作为Thread的target传入参数创建线程,另外一种是实现Callable接口的实现类,实现Callable接口时,需要重写call()方法,该方法和run()类似,都是线程的执行体,但是call()方法有返回值,必须要强调的一点,如果通过target方式创建新的线程,必须要实现runnable()接口的实现类才能作为参数传入Thread类来创建线程,Callable()接口和Runnable()接口完全没有任何关系,那么怎样实现runnable接口传入呢?

    刚才讲过,实现Callable接口的类必须重写有返回值的call()方法,Callable接口是泛型接口,call()方法返回值作为Futuretask类的泛型类参数,而FutureTask类实现了Future接口和Runnable接口,(接口直接可以多继承),同时Callable接口只有一个抽象方法,所以为了便捷,可以传入Lambda表达式创建Callable对象,将Callable对象作为FutureTask类的类型参数,然后就可以作为target传入啦。

public class Runtest {
    public static void main(String[] args) {
        Runtest test = new Runtest();
        FutureTask<Integer> task = new FutureTask<>((Callable<Integer>)()->{
           int i = 0;
           for(;i<100;i++) {
               System.out.println(Thread.currentThread().getName()+"循环变量i的值"+i);
           }
           return i;
        });
        for(int i=0 ;i<100;i++) {
            System.out.println(Thread.currentThread().getName());
            if(i==20)
            {
                new Thread(task,"有返回值的线程").start();
            }
        }
            try {
                System.out.println(Thread.currentThread().getName()+"这里是我的标记");
                
                System.out.println("子线程的返回值:"+task.get());
                if(task.isDone()) {
                    System.out.println("任务已经完成啦!");
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
            
        }
        
    }

public class Runtest {
public static void main(String[] args) {
Runtest test = new Runtest();
FutureTask<Integer> task = new FutureTask<>((Callable<Integer>)()->{
int i = 0;
for(;i<100;i++) {
System.out.println(Thread.currentThread().getName()+"循环变量i的值"+i);
}
return i;
});
for(int i=0 ;i<100;i++) {
System.out.println(Thread.currentThread().getName());
if(i==20)
{
new Thread(task,"有返回值的线程").start();
}
}
try {
System.out.println(Thread.currentThread().getName()+"这里是我的标记");

System.out.println("子线程的返回值:"+task.get());
if(task.isDone()) {
System.out.println("任务已经完成啦!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

}

  既然第二种方式这么复杂,为什么还要介绍这种呢,直接实现Runnable接口不就好了吗?优势主要有:

call()方法有返回值,并且可以抛出异常,同时Futuretask提供了一系列方法可以掌握任务的执行情况,检查计算是否完成等,也可以取消任务,相对于run()方法更为强大,

还可以加入线程池等……

  笔记: 采用Runnable、Callable接口方式创建多线程的优缺点:

    1、线程类只是实现了Runable接口或者Callable接口,还可以继承其他类。

    2. 在这种方式下,多个线程可以共享 一个target对象,所以非常适合多个相同线程来处理同一份资源的情况。从而可以将cpu 、代码和数据分离,形成清晰地模型,较好的体现了面向对象的思想

   缺点:编程复杂。

 

posted @ 2018-05-15 23:31  林冲—first  阅读(158)  评论(0编辑  收藏  举报