前言
我们一直都知道, Java内的多线程主要有2种方式. 同步方式和异步方式. 同步方式, 我们一般是使用Runnbale
接口; 异步方式, 我们一般使用的是Callable
接口.
我们今天就来详细的看一下这2个接口, 以及相关的使用和实现.
相关接口
- Runnable
作为Java实现多线程的入门级接口. 相信大家都不会非常陌生. 其相关实现, 如下所示:
/*
* Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package java.lang;
/**
* The <code>Runnable</code> interface should be implemented by any
* class whose instances are intended to be executed by a thread. The
* class must define a method of no arguments called <code>run</code>.
* <p>
* This interface is designed to provide a common protocol for objects that
* wish to execute code while they are active. For example,
* <code>Runnable</code> is implemented by class <code>Thread</code>.
* Being active simply means that a thread has been started and has not
* yet been stopped.
* <p>
* In addition, <code>Runnable</code> provides the means for a class to be
* active while not subclassing <code>Thread</code>. A class that implements
* <code>Runnable</code> can run without subclassing <code>Thread</code>
* by instantiating a <code>Thread</code> instance and passing itself in
* as the target. In most cases, the <code>Runnable</code> interface should
* be used if you are only planning to override the <code>run()</code>
* method and no other <code>Thread</code> methods.
* This is important because classes should not be subclassed
* unless the programmer intends on modifying or enhancing the fundamental
* behavior of the class.
*
* @author Arthur van Hoff
* @see java.lang.Thread
* @see java.util.concurrent.Callable
* @since JDK1.0
*/
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
可以看到. 这个接口的定时是1994
年, 在Java 1.0
的时候就已经定义好了.
使用这个接口也非常简单. 只需要实现这个接口, 随后将其塞入一个实际的线程中即可. 示例代码如下所示:
package com.yanxml.arsenal.multi;
/**
* Runnable 实现.
* @author sean
* @date 2021-11-28 00:00
*/
public class RunnableTest {
/**
* 示例代码1: 使用Runnable.
*/
public static void testMethod1(){
Runnable startRunningTask = new StartRunning();
Thread runThread = new Thread(startRunningTask);
runThread.start();
}
/**
* 示例代码2: 匿名函数写法.
*/
public static void testMethod2(){
Thread runThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Start Running...");
}
});
runThread.start();
}
/**
* 示例代码3: lambda表达式写法
*/
public static void testMethod3(){
Thread runThread = new Thread(() -> System.out.println("Start Running Lambda."));
runThread.start();
}
public static void main(String[] args) {
// 基础Running 接口写法.
testMethod1();
// 匿名函数写法
testMethod2();
// lambda表达式写法
testMethod3();
}
}
class StartRunning implements Runnable{
@Override
public void run() {
System.out.println("Start Running.");
}
}
Callable & Future
当我们进行在Java内需要使用异步操作时, 就经常会使用到Callable
和Future
. 我们仔细了解下这2个接口的相关实现.
- Callable
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package java.util.concurrent;
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
可以看到Callable
接口是JDK 1.5
才开始定义并且开始使用的. 其中也是只定义了一个接口, 与Runnable
不同的是, 其返回值为V
, 而Runnable
的返回值为void
. 即是可以获取到返回值的.
- FutureTask & Callable的相关使用
由于在Java内, 不论是单线程还是线程池. 基本上只认Thread
和Runnable
接口. 所以, 我们在使用Callable
的时候. 也还是都需要再做一层的封装的.
# RunnableFuture
package java.util.concurrent;
/**
* A {@link Future} that is {@link Runnable}. Successful execution of
* the {@code run} method causes completion of the {@code Future}
* and allows access to its results.
* @see FutureTask
* @see Executor
* @since 1.6
* @author Doug Lea
* @param <V> The result type returned by this Future's {@code get} method
*/
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
RunnableFuture
. Runnable
和Future
2个接口的结合体.
public class FutureTask<V> implements RunnableFuture<V> {
public void run() {
// 当前Thread状态是否是New状态
# 当前线程是否是Thread.currentThread() 即是否轮到当前线程进行执行
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
// ran用来记录是否执行成功
boolean ran;
try {
// 调用callable接口实现. 并获取返回值.
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
// 如果执行成功, 有返回值
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
# 方便JVM回收
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
}
- 由上可以看到. 我们使用了
Runnable
接口方法, 又包了一层, 用于方便外层调用. 其中, 还是调用了Callable
接口的call()
方法进行实现的.
–
Others
由于时间原因. 目前此处只介绍下run方法. 稍后再补充下其他几个方法. cancel()
和get()
方法.