一、通过继承Thread类来创建线程类

实现步骤:1.定义一个类继承Thread并重写Thread类中的run方法,run方法的方法体就是线程要完成的任务

2.创建该类的实例对象

3.调用线程对象的start方法来启动线程。

二、通过实现Runnable接口

1.定义一个类实现Runnable接口

2.创建该类的实例对象obj

3.将obj作为构造参数传入Thread类实例对象,这个对象才是真正的线程对象

4.调用线程对象的start方法启动线程

三、通过Callable接口创建线程

从JAVA 5开始,JAVA提供提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大,call()方法的功能的强大体现在:

1、call()方法可以有返回值;

2、call()方法可以声明抛出异常;

Callable接口是JAVA新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。还有一个原因就是:call()方法有返回值,call()方法不是直接调用,而是作为线程执行体被调用的,所以这里涉及获取call()方法返回值的问题。

于是,JAVA5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该类实现了Future接口,并实现了Runnable接口,所以FutureTask可以作为Thread类的target,同时也解决了Callable对象不能作为Thread类的target这一问题。

public class CallableTest implements Callable{
public String call() throws Exception{
return "hello world";
}
static void main(String[] args){
FutureTask task = new FutureTask(new CallableTest());
new Thread(task).start();
System.out.println(task.get());
}
}

上述方式的优缺点

通过继承Thread类实现多线程:

优点:

1、实现起来简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程;

缺点:

1、线程类已经继承Thread类了,就不能再继承其他类;

2、多个线程不能共享同一份资源(如前面分析的成员变量 i );

通过实现Runnable接口或者Callable接口实现多线程:

优点:

1、线程类只是实现了接口,还可以继承其他类;

2、多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况。

缺点:

1、通过这种方式实现多线程,相较于第一类方式,编程较复杂;

2、要访问当前线程,必须调用Thread.currentThread()方法。

第四种方式:利用线程池来提交任务创建线程

使用线程池的优点:

1.使用线程池可以重复利用线程,从而减小线程创建和销毁的开销

2.当任务到达的时候,不需要等待线程的创建,直接执行。提高响应速度

3.使用线程池可以对线程进行统一分配,调优和监控,从而不会过多消耗系统资源。

start方法和run方法的区别:

只有调用了start方法,才会启动线程,表现出多线程并发的特性即不同线程中run方法的代码交替执行。如果只是调用了run方法,那么代码还是同步执行的必须等待run方法里面的代码全部执行完了之后,才能够继续执行调用run方法线程中的代码

Runnable接口和Callable接口的区别:

Runnable接口中的run方法返回值是void,它做的事情只是纯粹地去执行run方法中的代码而已,至于是否执行完毕,执行了多久?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已;Callable+Future接口可以获取多线程运行的结果。如果线程长时间没有返回需要结果也可以取消。

java 多线程 网络请求 java多线程请求接口_java创建多线程的接口

wait方法立即释放锁,notify/notifyAll方法则是会等待线程剩余代码执行完毕之后才会释放对象锁