最新消息:我们是一群和平年代充满浮躁与抱怨的程序猿,心中充满抱负却无处撒野,明明是一匹野马,却找不到草原。

Java实现多线程的几种方法和区别

技术经验 goomoon 2489浏览 0评论

说起java多线程编程,大家都不陌生,下面我就总结下java里实现多线程的集中方法:

1、继承Thread类

方法:继承Thread类,重写run()方法,实例化线程类,调用start()方法启动线程。
代码如下:

这里有一个小知识点,我觉得挺有意思,那就是:

第一种方法:

第二种方式:

这两种方式有什么区别呢??

第一种方式,是另外起一个线程,至于这个线程具体的执行时间需要靠JVM内部线程调度器进行调度来决定何时进行轮询执行,而第二种方式呢,就和一个普通Java类一样,并没有新起一个线程,而是作为一个普通的类对象执行方法,并且是立即执行

2、实现Runnable接口

方法:实现Runnable接口并重写Run()方法,创建Runnable实例,并以此实例作为Thread类的target参数创建Thread对象,调用Thread对象的start()启动线程

代码如下:

其实 这两种实现方式,是java里最典型的两种实现方式。除了这两种方法呢,Java里还提供了第三种方式:Callable接口,看起来很像Runnable接口的增强版,不过其提供了一个call()方法作为线程执行体。但是call()比run()方法更加强大,因为最重要的点:call()可以有返回值。下面就仔细看下怎么用Callable接口来创建线程类。

3、使用Callable接口和Future来创建线程

Callable 不是 Runnable接口的子接口,不能直接作为Thread类的target参数。所以呢??看Java API可以了解,Java里有个FutureTask类实现了Future接口,更重要的是FutureTask类还实现了Runnable接口,这样就可以作为Thread类的target被执行了。

方法:实现Callable接口,并实现call()方法,并创建Callable实例,然后使用FutureTask对象来包装Callable实例,使用FutureTask对象作为Thread的target来创建并启动线程

代码如下:

如上面代码所示,在后面可以通过

来获取线程的返回值,这也是线程之间通信的一种方式呢。上面有一段代码:

咋一看,好像是在FutureTask的构造函数里声明了一个匿名内部类,仔细看呢又不太像,这一种写法其实是Java8里的一种新特性:Lambda表达式,使用Lambda表达式直接创建函数式接口的实例。其实和下面一种写法一致:

总结:根据上面三种方式呢都可以实现多线程,不过Runnable接口和Callable接口的方式基本相同(实现Runnable接口和Callable接口仅仅是创建了一个任务,但是仍然需要Thread类来创建线程并启动),他俩唯一区别只是Callable接口实现方法有返回值,并且也可以声明抛出异常而已,因此②和③可以归为一类,下面主要讨论和①中方法的区别和优缺点:

1、方法②和③,不仅实现了Runnable接口和Callable接口,还可以继承其他类,可拓展性比较好

2、多个线程共享一个target,所以更适合多线程共享统一资源。

3、第①中方法,实现起来比较简单,但是不太适合多个线程共享一个资源的情况。

4、还有一个小小的区别,就是在线程执行体里调用当前线程的方式不一样,在Thread子类的run()方法里可以直接使用this获取当前线程,而在Runnable和Callable的run()实现里,只能通过Thread.currentThread()来获取。

鉴于上面的分析,因此一般推荐采用Runnable接口或者Callable接口来实现多线程。

转载请注明:刘召考的博客 » Java实现多线程的几种方法和区别