启动线程的三种方式
Thread
第一种,通过继承Thread类创建线程类
1、定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程要完成的任务,因此把run()称为线程的执行体;
2、创建该类的实例对象,即创建了线程对象;
3、调用线程对象的start()方法来启动线程;
Runnable
这种方式创建并启动多线程的步骤如下:
1、定义一个类实现Runnable接口;
2、创建该类的实例对象obj;
3、将obj作为构造器参数传入Thread类实例对象,这个对象才是真正的线程对象;
4、调用线程对象的start()方法启动该线程;
Callable和Future
这种方式创建并启动多线程的步骤如下:
1、创建Callable接口实现类,并实现call()方法,该方法将作为线程执行体,且该方法有返回值,再创建Callable实现类的实例;
2、使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
3、使用FutureTask对象作为Thread对象的target创建并启动新线程;
4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
在Future接口里定义了如下几个公共方法来控制与它关联的Callable任务:
1、boolean cancel(boolean mayInterruptIfRunning):试图取消Future里关联的Callable任务;
2、V get():返回Callable任务里call()方法的返回值,调用该方法将导致程序阻塞,必须等到子线程结束以后才会得到返回值;
3、V get(long timeout, TimeUnit unit):返回Callable任务里call()方法的返回值。该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间后,Callable任务依然没有返回值,将会抛出TimeoutException异常;
4、boolean isCancelled():如果Callable任务正常完成前被取消,则返回true;
5、boolean isDone():如果Callable任务已经完成, 则返回true;
下面我们来分析一下这两类实现多线程的方式的优劣:
通过继承Thread类实现多线程:
优点:
1、实现起来简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程;
缺点:
1、线程类已经继承Thread类了,就不能再继承其他类;
2、多个线程不能共享同一份资源(如前面分析的成员变量 i );
通过实现Runnable接口或者Callable接口实现多线程:
优点:
1、线程类只是实现了接口,还可以继承其他类;
2、多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况。
缺点:
1、通过这种方式实现多线程,相较于第一类方式,编程较复杂;
2、要访问当前线程,必须调用Thread.currentThread()方法。