详解多线程启动涉及的知识点

JAVA乐园

共 3173字,需浏览 7分钟

 ·

2022-06-18 01:28


Thread类

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易实现资源共享。实现Runnable接口比继承Thread类所具有的优势:

  • 适合多个相同的程序代码的线程去处理同一个资源

  • 可以避免java中的单继承的限制

  • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

//继承 ThreadThread1 mTh1=new Thread1("A");Thread1 mTh2=new Thread1("B");mTh1.start();mTh2.start();

Runnable接口

// 先看一下java.lang.Runnable,它是一个接口,在它里面只声明了一个run()方法:// 由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。public interface Runnable {    public abstract void run();}
//实现Runnable接口Thread2 mTh = new Thread2();new Thread(mTh, "C").start();//同一个mTh,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常 new Thread(mTh, "D").start();new Thread(mTh, "E").start();

这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。

而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Callable接口

Callable接口位于java.util.concurrent包下,在它里面也只声明了一个方法,只不过这个方法叫做call()。

public interface Callable<V> {    V call() throws Exception;}

可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。Callable接口可以看作是Runnable接口的补充,call方法带有返回值,并且可以抛出异常。

FutureTask类

如何获取Callable的返回结果呢?一般是通过FutureTask这个中间媒介来实现的。整体的流程是这样的:

  • 把Callable实例当作参数,生成一个FutureTask的对象

  • 然后把这个对象当作一个Runnable,作为参数另起线程。

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。下面以Thread包装线程方式启动来说明一下。

import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;
public class Demo {    public static void main(String[] args) throws Exception {        Callable<Integer> call = new Callable<Integer>() {            public Integer call() throws Exception { System.out.println("计算线程正在计算结果..."); Thread.sleep(3000); return 1; } };
        FutureTask<Integer> task = new FutureTask<>(call); Thread thread = new Thread(task);        thread.start(); System.out.println("main线程干点别的..."); Integer result = task.get(); System.out.println("从计算线程拿到的结果为:" + result); }}

Future接口

FutureTask继承体系中的核心接口是Future。

Future的核心思想是:一个方法,计算过程可能非常耗时,等待方法返回,显然不明智。可以在调用方法的时候,立马返回一个Future,可以通过Future这个数据结构去控制方法f的计算过程。这里的控制包括:

public interface Future<V{    boolean cancel(boolean mayInterruptIfRunning);//还没计算完,可以取消计算过程    boolean isCancelled();///判断计算是否被取消    boolean isDone();//判断是否计算完    V get() throws InterruptedException, ExecutionException;    //获取计算结果(如果还没计算完,也是必须等待的)    V get(long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException;}

也就是说Future提供了三种功能:

  • 判断任务是否完成;

  • 能够中断任务;

  • 能够获取任务执行结果。

实现Runnable接口和Callable接口的区别

如果想让线程池执行任务的话需要实现的Runnable接口或Callable接口。

Runnable接口或Callable接口实现类都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。两者的区别在于 Runnable 接口不会返回结果但是 Callable 接口可以返回结果。

备注:工具类 Executors 可以实现 Runnable 对象和 Callable 对象之间的相互转换。
Executors.callable(Runnable task)也就是说Future提供了三种功能:

  • 判断任务是否完成;

  • 能够中断任务;

  • 能够获取任务执行结果。Executors.callable(Runnable task,Object resule )。

记得点「」和「在看」↓

爱你们

浏览 28
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报