android中的多线程之多线程的基本知识

与多线程相关的方法—-Callable,Future和FutureTask

除了Runnable之外,Java中还有Callable,Futrue,FutureTask这几个与多线程相关的概念,与Runnable不同的是这几个类都只能运用到线程池中,而Runnable既能运用到Thread中,又能运用到线程池中。

Callable

Callable与Runnable的功能大致相似,不同的是Callable是一个泛型接口,它有一个泛型参数V,该接口中有一个返回值(类型为V)的call()方法,而Runnable的run()方法不能将结果返回:

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

Future为线程池指定了一个可管理的任务标准。它提供了对Runnable或者Callable任务的执行结果进行取消,查询是否完成,获取结果,设置结果操作:

public interface Future<V> {

/**
    尝试去取消这个任务的执行,但是这个尝试有可能失败,当这个任务已经完成或者取消的时候,或者因为其他原因。
    如果该任务已经开始执行了,将由mayInterruptIfRunning这个参数来决定是否打断任务的执行。
 *
 */
boolean cancel(boolean mayInterruptIfRunning);

/**
 该任务是否取消
 * */
boolean isCancelled();

/**
 * Returns {@code true} if this task completed.
 * 该任务是否完成
 **/
boolean isDone();

/**
    获取结果,如果任务未完成,则等待,直到完成。因此该方法会阻塞
 **/
V get() throws InterruptedException, ExecutionException;

/**
    获取结果,如果任务未完成,直到timeout或者返回结果。该方法会阻塞
* */
V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;
}
FutureTask

在上面我们可以看到,Future只是定义了一些规范的接口,而FutureTask是它的实现类。
FutureTask实现了RunnableFture<V>,而RunnableFuture又实现了RunnableFuture<V>,因此FutureTaske具备它们的能力。

public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
    * */
    void run();
}

FutureTask会像Thread包装Runnable一样,对CallableRunnable进行包装:

 public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       // ensure visibility of callable
}

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

我们可以看到,当传入Runnable的时候,会用Executors.callable方法转换成Callable类型,即FutureTask最终执行的都是Callable类型的任务:

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

 private static final class RunnableAdapter<T> implements Callable<T> {
    private final Runnable task;
    private final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

我们可以看到在用Runnable构造FutureTask的时候,会将Runnable包装为一个RunnableAdapter,在它的Call方法中,其实是执行的Runnable的run方法,但是返回是我们在构造FutureTask的时候传入的result,如果我们不是特别需要它,可以传入null。

了解基本概念后,通过代码来演示Runnable,Callable,FutureTask的运用:

public class FutureDemo {

//线程池
static ExecutorService mExecutor = Executors.newSingleThreadExecutor();

public static void main(String[] args){
    try {

        futureWithRunnable();
        futureWithCallable();
        futureTask();

    }catch(Exception e){

    }
}

//向线程池中提交Runnable对象
private static void futureWithRunnable()throws InterruptedException,ExecutionException{
    Future<?> result = mExecutor.submit(new Runnable() {
        @Override
        public void run() {
             fibc(20);
        }
    });

    System.out.println("future result form runnable : "+result.get() );
}


//提交Callable对象,有返回值
private static void futureWithCallable()throws InterruptedException,ExecutionException{
    Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return fibc(20);
        }
    });

    System.out.println("future result form callable : "+result2.get());
}

//提交FutureTask对象
private static void futureTask()throws InterruptedException,ExecutionException{

    FutureTask<Integer> futureTask = new FutureTask<>(
            new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    return fibc(20);
                }
            }
    );
    mExecutor.submit(futureTask);
    System.out.println("future result form futureTask : "+futureTask.get());
}

private static int fibc(int num){
    if(num ==0){
        return 0;
    }
    if(num == 1){
        return  1;
    }

    return fibc(num-1)+fibc(num-2);
}

}

执行的结果:

future result form runnable : null
future result form callable : 6765
future result form futureTask : 6765

在futureWithRunnable方法中提交了一个Runnable对象,在run方法中进行计算,该方法没有返回值,因此通过Future对象的get函数得到的值为null。
Callable实现的是V call方法,将Callable对象提交给线程池后会返回一个Future对象,通过该对象可以对任务进行取消,获取结果等操作。
FutrueTask是一个RunnableFuture,因此即实现了Runnable又实现了Future这两个接口,它可以包装Runnable(实际上会转为Callable)和Callable,提交给ExecuteService来执行后,也可以通过Future对象的get方法来得到结果。

那么这里面是如何运转的呢?不急,先要知道其他知识

线程池

当我们需要频繁创建多个线程进行耗时操作时,每次都通过new Thread实现并不是一种好方式,每次new Thread新建和销毁对象性能较差,线程缺乏统一的管理,可能无限制新建线程,相互之间竞争,可能占用过多系统资源导致死锁,并且缺乏定时执行,定期执行,线程中断等功能。
java通过Executor提供了四种线程池:

  1. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。—->ThreadPoolExecutor

  2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。—->ThreadPoolExecutor

  3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。—->ScheduledThreadPoolExecutor

  4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。—->ThreadPoolExecutor

优点:

  1. 重用存在的线程,减少对象创建,销毁的开销
  2. 可有效控制最大量并发线程数,提供系统资源的使用率,同时避免过多资源竞争,避免阻塞。
  3. 提供定时执行,定期执行,单线程,并发控制等功能。

线程池原理的简单解释就是会创建多个线程并且进行管理,提交给线程的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度,管理使得多线程的使用更简单,高效。

线程池都实现了ExecutorService接口,该接口定义了线程池需要实现的接口,如submit,execute,shutdown等。它的实现有ThreadPoolExecutor和ScheduledPoolExcutor。ThreadPoolExecutor是运用最多的线程池实现,ScheduledThreadPoolExecutor则用于周期性地执行任务。通常,我们都不会直接通过new的形式来创建线程池,由于常见参数过程相对复杂,因为JDK给我们提供了Executors工厂类来简化这份过程。

线程池的类图:

ExecutorService

ExecutorService的声明周期包括3中状态:运行,关闭,终止。创建后便进入到了运行状态。当调用shutdown()方法时,便进入到了关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务。当所有已经提交了的任务完成后,就变成了终止状态。

public interface ExecutorService extends Executor {

void shutdown();

boolean isShutdown();

boolean isTerminated();

boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException;

<T> Future<T> submit(Callable<T> task);


<T> Future<T> submit(Runnable task, T result);


Future<?> submit(Runnable task);

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
    throws InterruptedException;


<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                              long timeout, TimeUnit unit)
    throws InterruptedException;


<T> T invokeAny(Collection<? extends Callable<T>> tasks)
    throws InterruptedException, ExecutionException;


<T> T invokeAny(Collection<? extends Callable<T>> tasks,
                long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;
}

//用来执行被提交的任务,也就是一个运行新任务的简单接口
public interface Executor {

/**
 * Executes the given command at some time in the future.  The command
 * may execute in a new thread, in a pooled thread, or in the calling
 * thread, at the discretion of the {@code Executor} implementation.
 *
 * @param command the runnable task
 * @throws RejectedExecutionException if this task cannot be
 * accepted for execution
 * @throws NullPointerException if command is null
 */
void execute(Runnable command);
}
启动指定数量的线程:ThreadPoolExecutor

ThreadPoolExecutor是线程池的实现之一,它的功能时启动指定数量的线程以及将任务添加到一个队列中,并且将任务分发给空闲的线程。

它有四种构造方法:

public ThreadPoolExecutor(int corePoolSize,
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值