Java并发编程 一文看懂Callable和Runnable使用及原理

本文详细解析了Java并发编程中Callable和Runnable接口的使用及原理,对比了两者区别,介绍了在线程中的应用方式,分析了相关类如Executor、ExecutorService、Future、FutureTask的原理与功能。
摘要由CSDN通过智能技术生成

背景

安卓开发中很多时候,我们都是选择使用已有框架做异步任务,有些时候,线程一旦启动,不容易终止,此文解析下Runnable和Callable的使用,补充下基础知识。

一、Callable和Runnable

二者都是线程创建时执行耗时操作的位置,二者都只是一个接口,区别是Callable有返回值。

public interface Runnable {
    public abstract void run();
}
public interface Callable<V> {
	// call方法会返回V类型的结果
    V call() throws Exception;
}

二、Runnable在线程中的使用

Runnable需要依赖Thread或者ExecutorService使用,有三种使用方式

// 1、重写Thread的run方法
new Thread() {
	@Override
	public void run() {
	}
}.start();

// 2、创建Runnable对象作为参数
new Thread(new Runnable() {
	@Override
	public void run() {
	}
}).start();

// 3、借助于ExecutorService,使用submit或者execute,一般结合FutureTask使用
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(new Runnable() {
	@Override
	public void run() {
	}
});
executorService.execute(new Runnable() {
	@Override
	public void run() {
	}
});

本质上重写Thread的run方法本质也是Runnable对象

// Thread实现了Runnable接口
public class Thread implements Runnable {
	private Runnable target;
	
	public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        this.target = target;
    }
    
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

三、Callable在线程中的使用

Callable利用ExecutorService的submit方法去启动call方法

ExecutorService executorService = Executors.newFixedThreadPool(10);
// submit方法,会等待结果返回
Callable<String> stringCallable = new Callable<String>() {
	@Override
	public String call() throws Exception {
	}
};
Future<String> result = executorService.submit(stringCallable);

四、Callable&Runnable使用相关类原理解析

我们发现,Callable和Runnable的使用借用了Executor、ExecutorService、Executors、Future、FutureTask。并且这几个类都是很不错的实现,我们解析下这几个类的功能和原理。
1、Executor用于执行已提交Runnable任务的对象,接口类

public interface Executor {
    void execute(Runnable command);
}

2、Future用于获取异步任务的结果,接口类

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;
}

3、ExecutorService是对Executor接口的扩展,提供一些接口去操作任务集合,同时支持Callable,返回Future用于操作任务结果

public interface ExecutorService extends Executor {
	void shutdown();
	List<Runnable> shutdownNow();
	boolean isShutdown();
	// 如果所有任务都执行完了shutdown,返回true
	boolean isTerminated();
	// 阻塞直到所有任务执行完成或被shutdown或被中断
	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;
}

4、FutureTask继承Runnable,可以兼容Thread使用Runnable;实例化接收Runnable和Callable,任何任务都可被包装执行;实现了Future接口,可以取消任务,设置超时任务。

// 一个可被管理的Runnable
public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

public class FutureTask<V> implements RunnableFuture<V> {
	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) {
		// Executors的包装接口,用Callable包装了Runnable
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
	public boolean isCancelled() { return state >= CANCELLED;}
    public boolean isDone() {return state != NEW;}
    public boolean cancel(boolean mayInterruptIfRunning) {
		// 1、mayInterruptIfRunning为true,执行中也会被中断
		// 2、mayInterruptIfRunning为false,没执行的才会被取消
	}
	// 获取执行结果,这里可能被阻塞
    public V get() throws InterruptedException, ExecutionException {}
    // 规定时间内获取执行结果
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {}
    // 任务执行完成、被cancel、出现异常,会调用这个方法,可以重写此方法作为监听
	protected void done() { }
	// 任务执行完,调用此方法返回结果
	protected void set(V v) {}
	// 执行出现异常,调用此方法释放资源,设置任务状态
	protected void setException(Throwable t) {}
	// 这里会执行实例化传入的任务
	public void run() {}

5、Executors提供了一些工具方法,用来提供线程池,和包装类

// AbstractExecutorService实现了ExecutorService的submit、invokeAny、invokeAll接口
public abstract class AbstractExecutorService implements ExecutorService {
	public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    
	protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
		// 提交任务后返回的是FutureTask,说明可以利用FutureTask接口操作任务
        return new FutureTask<T>(runnable, value);
    }
    
	public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }

	public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
	}
}

// 这个类包装了线程池,用来执行任务.同时实现了ExecutorService的shutdown、isShutdown、isTerminated、awaitTermination接口
public class ThreadPoolExecutor extends AbstractExecutorService {
	public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
    // 其他实现就不列出了,有兴趣的可以自行了解源码
}

// 提供了一些方法用来创建ThreadPoolExecutor,包装Runnable
public class Executors {
	// 这里创建ThreadPoolExecutor,返回包装了可以操作任务的线程池
	public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    }
	
	// 返回了一个单线程的线程池
	public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
    }
	
	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;
        }
    }
    
	public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        // 这里其实是把Runnable包装成了Callable,同时绑定了返回值
        return new RunnableAdapter<T>(task, result);
    }
}

注:Executors可以创建很多类型的线程池,这里就不做具体分析,有需求可以阅读此类,选择合适的线程池操作。

五、一些不错的代码

1、实现一个封装好的有序执行的队列,在AsyncTask有使用。

class SerialExecutor implements Executor {
    final Queue<Runnable> tasks = new ArrayDeque<>();
    final Executor executor;
    Runnable active;
 
    SerialExecutor(Executor executor) {
      this.executor = executor;
    }
    
    public synchronized void execute(final Runnable r) {
      tasks.add(new Runnable() {
        public void run() {
          try {
            r.run();
          } finally {
            scheduleNext();
          }
        }
      });
      if (active == null) {
        scheduleNext();
      }
    }
 
    protected synchronized void scheduleNext() {
      if ((active = tasks.poll()) != null) {
        executor.execute(active);
      }
    }
}}

2、实现socket连接下request请求

  class NetworkService implements Runnable {
    private final ServerSocket serverSocket;
    private final ExecutorService pool;
 
    public NetworkService(int port, int poolSize)
        throws IOException {
      serverSocket = new ServerSocket(port);
      pool = Executors.newFixedThreadPool(poolSize);
    }
 
    public void run() { // run the service
      try {
        for (;;) {
          pool.execute(new Handler(serverSocket.accept()));
        }
      } catch (IOException ex) {
        pool.shutdown();
      }
    }
  }
 
  class Handler implements Runnable {
    private final Socket socket;
    Handler(Socket socket) { this.socket = socket; }
    public void run() {
      // read and service request on socket
    }
  }

总结

1、Callable的出现,使得任务可以有返回值。
2、Future的get和cancel等接口,使得线程可以被取消,可以随时get获取结果。
3、Executor接口用来执行Runnable
4、ExecutorService扩展了Executor,提供了shutdown接口,同时支持执行Runnable和Callable,和任务集合。返回Future,可以通过Future操作任务。这里我们可以发现,操作线程任务有两种方式,一种通过ExecutorService的shutdown,另一种通过Future的cancel方法。
5、Executors提供ThreadPoolExecutor等线程池包装类,用来执行异步任务,ThreadPoolExecutor同时实现了ExecutorService的接口,可以操作任务。
6、Future、FutureTask、Executor、ExecutorService、Executors的出现兼容了Runnable接口,同时支持了Runnable返回结果。并且提供了一些不错的包装类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值