线程驱动任务,而我们需要的就是一种任务的描述,而这个描述由Runable接口来提供,想定义任务,只需要实现Runable接口并重写里面的run()就好
Thread() 创建新线程对象
Thread(String name) 创建新线程对象
Thread(Runnable target) 创建新线程对象
Thread(Runnable target, String name) 创建新线程对象,name为指定的线程名
Thread(ThreadGroup group, Runnable target) 分配新的 Thread 对象。
Thread(Runnable target) 创建新线程对象
Thread构造器通常需要一个Runable对象,我们把需要执行的任务放在run()中,程序运行后,会自动执行Runable对象的run()方法,以便在新的线程中执行我们指定的任务. start()方法是告诉cpu线程处于就绪状态
一. 继承Thread 创建线程 public class demo01 extends Thread { public demo01(String name){ super.setName(name); } public demo01(){ } @Override public void run() { while(true) System.out.println(Thread.currentThread().getName()+"继承Thread类的线程执行了..."); } public static void main(String[] args) { //new demo01() 执行Thread空参构造方法... demo01 d = new demo01(); demo01 d2 =new demo01("helloThread"); //线程就绪 d.start(); d2.start(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } 二. 直接实现Runnable接口实现runable接口 其实demo02 本类并不是一个Thread 他是一个线程任务
public class demo02 implements Runnable{ @Override public void run() { // while(true) System.out.println(Thread.currentThread().getName()+"线程执行了..."); } public static void main(String[] args) { demo02 d = new demo02(); Thread myThread = new Thread(d); myThread.start(); //lamaban表达式实现的run方法 new Thread(()->{ while(true) System.out.println("lamaban表达式实现的run方法执行了..."); } ).start(); //直接写 new Thread(){ @Override public void run() { System.out.println("hello Thread.."); } }.start(); //实现Runable() + 继承Thread(); new Thread(new Runnable() { @Override public void run() { System.out.println("Runnable接口里面的run"); } }){ //子类覆盖了 父类的run方法... @Override public void run(){ System.out.println("Thread子类里面的run"); } }.start(); } }一般情况下,如果不是多继承,实现Runable接口和继承Thread类没啥区别
三. Callable 创建既有返回值,又可以抛出异常的线程Callable同样可以理解成是一个任务的描述方式,只不过他不能直接丢给Thread,而是交给一个叫FutrueTask的容器包装,
Callable&Runable的区别Callable规定的方法是call() 而后者是run()
Callable执行任务后可以拿到返回值,而后者不可以
call()方法,可以抛出异常,而run()方法不行
Callable更强大一些.运行Callable的任务,可以拿到一个Future的对象,我们可以先通过这个对象isDone()判断任务是否结束,然后调用get()获取运行的返回值
Future接口
一来说多个线程之间是异步执行的,我们很难从一条线程拿到另一条线程的返回值,这个时候Futrue就出场了,对于Callable和Runable提交过来的任务,他可以进行查询任务是否完成 isDone() 获取执行结果get() 取消任务cancel()
FutureTask类FutrueTask它的父类是RunableFuture而RunableFuture继承了Runable和Future,看他的血缘关系,FutureTask当然既可以作为任务被线程执行,又可以拿到它得到的Callable的返回值,
此外我们可以知道它最终也是执行Callable类型的接口,如果传递进来的是Runable的实现,那么它会先把他转化成Callable,
public class demo03 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("hello Callable"); //返回值的类型就是Callable接口的泛型 return 1; } public static void main(String[] args) throws ExecutionException, InterruptedException { //未来的任务 FutureTask<Integer> task = new FutureTask<>(new demo03()); new Thread(task).start(); System.out.println("返回值的结果是:"+task.get()); } }刚才提到,Thread接收的任务是Runable类型的,现在FutureTask是个什么鬼?怎么把它传递进来的? 其实,FutrueTask实现了RunnableFuture接口,而这个接口继承了Runnable&Future,一切也就那么顺其自然了
当然我们知道,Runable里面的run()方法是由新new出来的线程异步执行的,那么现在重写的这个call()怎么个运行法?