1.Thread类
- 一个线程在Java中使用一个Thread实例来描述。Thread类是Java语言一个重要的基础类,位于
java.lang
包中。Thread类有不少非常重要的属性和方法,用于存储和操作线程的描述信息。
1.1 线程ID
属性: private long tid,此属性用于保存线程的ID。这是一个private类型属性,外部只能使用
getId()
方法进行访问线程的ID.方法: public long getld(),获取线程ID,线程ID由JVM进行管理,在进程内唯一。
1.2 线程名称
属性: private String name,该属性保存一个Thread线程实例的名字。
方法一: public final String getName(),获取线程名称。
方法二: public final void setName(String name),设置线程名称。
方法三: Thread(String threadName),通过此构造方法给线程设置一个定制化的名字。
1.3 线程优先级
属性: private int priority,保存一个Thread线程实例的优先级。
方法一: public final int getPriority(),获取线程优先级。
方法二: public final void setPriority(int priority),设置线程优先级。
- Java线程优先级的最大值为10,最小值为1,默认值为5。这三个优先级值为三个常量值,也是在Thread类中使用类常量定义,三个类常量如下:
public static final int MIN_PRIORITY=1;
public static final int NORM_PRIORITY=5;
public static final int MAX_PRIORITY=10:
1.4 是否为守护线程
属性: private boolean daemon=false,该属性保存Thread线程实例的守护状态,默认为
false
,表示是普通的用户线程,而不是守护线程。
方法:public final void setDaemon(boolean on),将线程标记为守护线程或用户线程,如果参数值为true
,那么将线程实例标记为守护线程。
1.5 线程的状态
属性: private int threadStatus,该属性以整数的形式保存线程的状态。
方法: public Thread.State getState(),返回表示当前线程的执行状态,为
新建
、就绪
、运行
、阻塞
、结束
等状态中的一种。
public enum State {
NEW, // 新建
RUNNABLE,// 就绪、运行
BLOCKED,// 阻塞
WAITING, // 等待
TIMED_WAITING, // 计时等待
TERMINATED; // 结束
}
- 在Java线程的状态中,就绪状态和运行状态在内部都用同一种状态
RUNNABLE
表示。就绪状态表示线程具备运行条件,正在等待获取CPU时间片:运行状态表示线程已经获取了CPU时间片,CPU正在执行线程代码逻辑。
1.6 线程的启动和运行
方法一: public void start(),用来启动一个线程,当调用start()方法后,JVM才会开启一个新的线程来执行用户定义的线程代码逻辑,在这个过程中会为相应的线程分配需要的资源。
方法二: public void run(),作为线程代码逻辑的入口方法。run()方法不是由用户程序来调用的,当调用start()方法启动一个线程之后,只要线程获得了CPU执行时间,便进入run()方法去执行具体的用户线程代码。start()法用于线程的启动,run()方法作为用户代码逻辑的执行入口。
1.7 取得当前线程
方法: public static Thread currentThread(),该方法是一个非常重要的
静态方法
,用于获取当前线程的Thread实例对象。什么是当前线程呢? 就是当前在CPU上执行的线程。在没有其他的途径获取当前线程的实例对象的时候,可以通过Thread.currentThread()静态方法获取。
2.创建线程的几种方式
2.1 继承 Thread 类创建线程类(方法1)
- 需要继承Thread类,创建一个新的线程类。
- 同时重写run()方法,将需要并发执行的业务代码编写在run()方法中。
public class DemoThread extends Thread {
private static int threadNo = 0;
public DemoThread() {
super("Mall-" + threadNo++);
}
public void run() {
// TODO
}
}
2.2 实现 Runnable 接口创建线程(方法2)
public Thread(Runnable target)
public Thread(Runnable target, String name)
public Thread(ThreadGroup group, Runnable target)
public class RunTarget implements Runnable {
public void run() {
// TODO
}
public static void main(String args[]){
private static int threadNo = 0;
Thread thread = new Thread(new RunTarget(),"name" + threadNo++);
}
}
2.3 Callable 和 FutureTask 系列接口
- 继承Thread类或者实现Runnable接口这两种方式来创建线程类,不能获取异步执行的结果。
- Java语言在1.5版本之后提供了一种新的多线程创建方法:通过Callable接口和FutureTask类相结合创建线程,解决异步执行的结果问题。
2.3.1 Callable接口
- Callable接口是一个泛型接口,是一个函数式接口。
- 其唯一的抽象方法call()有返回值,返回值的类型为Callable接口的泛型形参类型。
- call()抽象方法还有一个Exception的异常声明,容许方法的实现版本的内部异常直接抛出,并且可以不予捕获。
Callable实例能否和Runnable实例一样,作为Thread线程实例的target来使用呢?
答案是不行。Thread的target属性的类型为Runnable,而Callable接口与Runnable接口之间没有任何继承关系,并且二者唯一的方法在名字上也不同。显而易见,Callable接口实例没有办法作为Thread线程实例的target来使用。需要一个在Calable接口与Thread线程之间起到搭桥作用的重要接口。
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
2.3.2 RunnableFuture 接口
- 该接口与Runnable接口、Thread类紧密相关。
- 与Callable接口一样RunnableFuture接口也位于
java.util.concurrent
包中,使用时需要用import导入。 - RunnableFuture是如何在Callable与Thread之间实现搭桥功能的呢? RunnableFuture接口实现了两个目标
- 一是可以作为Thread线程实例的target实例,
- 二是可以获取异步执行的结果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
RunnableFuture继承了Runnable接口,从而保证了其实例可以作为Thread线程实例的target日标;
同时,RunnableFuture通过继承Future接口,保证了通过它可以获取未来的异步执行结果。
2.3.3 Future 接口
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;
}
对Future接口的主要方法详细说明如下:
V get()
: 获取异步任务执行的结果。注意,这个方法的调用是阻塞性
的。如果异步任务没有执行完成,异步结果获取线程(调用线程)会一直被阻塞,一直阻塞到异步任务执行完成,其异步结果返回给调用线程。V get(Long timeout,TimeUnitunit)
: 设置时限,(调用线程)阻塞性地获取异步任务执行的结果。该方法的调用也是阻塞性的,但是结果获取线程(调用线程)会有一个阻塞时长限制,不会无限制地阻塞和等待,如果其阻塞时间超过设定的timeout时间,该方法将抛出异常,调用线程可捕获此异常。boolean isDone()
:获取异步任务的执行状态。如果任务执行结束,就返回true
。boolean isCancelled()
:获取异步任务的取消状态。如果任务完成前被取消,就返回true。boolean cancel(boolean mayInterruptRunning)
:取消异步任务的执行。
总体来说,Future是一个对异步任务进行交互、操作的接口。但是Future仅仅是一个接口,通过它没有办法直接完成对异步任务的操作,JDK提供了一个默认的实现类
FutureTask
。
2.4 FutureTask 类
- FutureTask类是Future接口的实现类,提供了对异步任务的操作的具体实现。
- FutureTask类不仅仅实现了Future接口,还实现了Runnable接口,或者更加准确地说,FutureTask类实现了RunnableFuture接口。
- RunnableFuture接口既可以作为Thread线程实例的target日标,也可以获取并发任务执行的结果,是Thread与Callable之间一个非常重要的搭桥角色。
- RunnableFuture是一个接口,无法直接创建对象,如果需要创建对象,就需用到它的实现类FutureTask。所以说FutureTask类才是真正的在Thread与Callable之间搭桥的类。
从FutureTask类的UML关系图可以看到:FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable接口和Future接口,所以FutureTask既能当作一个Runnable类型的target执行目标直接被Thread执行,又能作为Future异步任务来获取Callable的计算结果。
FutureTask如何完成多线程的并发执行、任务结果的异步获取呢?FutureTask内部有一个Callable类型的成员callable实例属性。
private Callable<V> callable;
- callable 实例属性用来保存并发执行的
Callable<V>
类型的任务,并且callable实例属性需要在FutureTask实例构造时进行初始化。FutureTask类实现了Runnable接口,在其run()方法的实现版本中会执行callable成员的call()方法。 - FutureTask内部还有另一个非常重要的Obiect 类型的成员
outcome
实例属性:
private Object outcome;
- FutureTask的outcome实例属性用于保存callable成员
call()
方法的异步执行结果。在FutureTask类run()方法完成callable成员的call()方法的执行之后,其结果将被保存在outcome实例属性中,供FutureTask类的get()方法获取。
2.5 Callable 和 FutureTask 创建线程(方法3)
通过FutureTask类和Callable接口的联合使用可以创建能获取异步执行结果的线程。具体步骤如下:
- 创建一个Callable接口的实现类,并实现其call()方法,编写好异步执行的具体逻辑,可以有返回值。
- 使用Callable实现类的实例构造一个FutureTask实例。
- 使用FutureTask实例作为Thread构造器的target入参,构造新的Thread线程实例。
- 调用Thread实例的start()方法启动新线程,启动新线程的run()方法并发执行。其内部的执行过程为:启动Thread实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执Callable实现类的call()方法。
- 调用FutureTask对象的get()方法阻塞性地获得并发线程的执行结果。
public class ReturnableTask implements Callable<Long> {
public Long call() throws Exception {
long startTime = System.currentTimeMillis();
Thread.sleep(1000);
// TODO
long used = System.currentTimeMillis() - startTime;
return used;
}
}
public class Demo {
public static final int MAX_TURN = 5;
public static final int COMPUTE_TIMES = 100000000;
public static void main(String args[]) throws InterruptedException {
// callable接口的具体实现
ReturnableTask task = new ReturnableTask();
// 传入callable接口
FutureTask<Long> futureTask = new FutureTask<Long>(task);
// 传入futureTask
Thread thread = new Thread(futureTask, "returnableThread");
thread.start();
Thread.sleep(500);
for (int i = 0; i < COMPUTE_TIMES / 2; i++) {
int j = i * 10000;
}
try {
System.out.println(thread.getName() + "线程占用时间:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
- futureTask的结果outcome不为空,callable.call()执行完成。在这种情况下,futureTast.get会直接取回outcome结果,返回给main线程(结果获取线程)。
- futureTask的结果outcome为空,callable.call()还没有执行完。在这种情况下,main线程作为结果获取线程会被阻塞住,一直被阻塞到callable.cal()执行完成。当执行完后,最终结果保存到outcome中,futureTask会唤醒main线程去提取callable.call()执行结果。
2.6 通过线程池创建线程(方法4)
- 前三种方式所创建的Thread实例在执行完成之后都销毁了,这些线程实例都是不可复用的。
- 实际上创建一个线程实例在时间成本、资源耗费上都很高的,在高并发的场景中,断然不能频繁进行线程实例的创建与销毁,而是需要对已经创建好的线程实例进行复用,Java中提供了一个静态工厂来创建不同的线程池,该静态工厂为
Executors
工厂类。
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
if (executor == null)
throw new NullPointerException();
return new DelegatedExecutorService(executor);
}
public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
if (executor == null)
throw new NullPointerException();
return new DelegatedScheduledExecutorService(executor);
}
public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}
public static ThreadFactory privilegedThreadFactory() {
return new PrivilegedThreadFactory();
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
public static Callable<Object> callable(Runnable task) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<Object>(task, null);
}
public static Callable<Object> callable(final PrivilegedAction<?> action) {
if (action == null)
throw new NullPointerException();
return new Callable<Object>() {
public Object call() { return action.run(); }};
}
public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
if (action == null)
throw new NullPointerException();
return new Callable<Object>() {
public Object call() throws Exception { return action.run(); }};
}
public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
if (callable == null)
throw new NullPointerException();
return new PrivilegedCallable<T>(callable);
}
public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
if (callable == null)
throw new NullPointerException();
return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
}
// Non-public classes supporting the public methods
/**
* A callable that runs given task and returns given result
*/
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
/**
* A callable that runs under established access control settings
*/
static final class PrivilegedCallable<T> implements Callable<T> {
private final Callable<T> task;
private final AccessControlContext acc;
PrivilegedCallable(Callable<T> task) {
this.task = task;
this.acc = AccessController.getContext();
}
public T call() throws Exception {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<T>() {
public T run() throws Exception {
return task.call();
}
}, acc);
} catch (PrivilegedActionException e) {
throw e.getException();
}
}
}
/**
* A callable that runs under established access control settings and
* current ClassLoader
*/
static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> {
private final Callable<T> task;
private final AccessControlContext acc;
private final ClassLoader ccl;
PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Calls to getContextClassLoader from this class
// never trigger a security check, but we check
// whether our callers have this permission anyways.
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
// Whether setContextClassLoader turns out to be necessary
// or not, we fail fast if permission is not available.
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
this.task = task;
this.acc = AccessController.getContext();
this.ccl = Thread.currentThread().getContextClassLoader();
}
public T call() throws Exception {
try {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<T>() {
public T run() throws Exception {
Thread t = Thread.currentThread();
ClassLoader cl = t.getContextClassLoader();
if (ccl == cl) {
return task.call();
} else {
t.setContextClassLoader(ccl);
try {
return task.call();
} finally {
t.setContextClassLoader(cl);
}
}
}
}, acc);
} catch (PrivilegedActionException e) {
throw e.getException();
}
}
}
/**
* The default thread factory
*/
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
/**
* Thread factory capturing access control context and class loader
*/
static class PrivilegedThreadFactory extends DefaultThreadFactory {
private final AccessControlContext acc;
private final ClassLoader ccl;
PrivilegedThreadFactory() {
super();
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Calls to getContextClassLoader from this class
// never trigger a security check, but we check
// whether our callers have this permission anyways.
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
// Fail fast
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
this.acc = AccessController.getContext();
this.ccl = Thread.currentThread().getContextClassLoader();
}
public Thread newThread(final Runnable r) {
return super.newThread(new Runnable() {
public void run() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
Thread.currentThread().setContextClassLoader(ccl);
r.run();
return null;
}
}, acc);
}
});
}
}
/**
* A wrapper class that exposes only the ExecutorService methods
* of an ExecutorService implementation.
*/
static class DelegatedExecutorService extends AbstractExecutorService {
private final ExecutorService e;
DelegatedExecutorService(ExecutorService executor) { e = executor; }
public void execute(Runnable command) { e.execute(command); }
public void shutdown() { e.shutdown(); }
public List<Runnable> shutdownNow() { return e.shutdownNow(); }
public boolean isShutdown() { return e.isShutdown(); }
public boolean isTerminated() { return e.isTerminated(); }
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return e.awaitTermination(timeout, unit);
}
public Future<?> submit(Runnable task) {
return e.submit(task);
}
public <T> Future<T> submit(Callable<T> task) {
return e.submit(task);
}
public <T> Future<T> submit(Runnable task, T result) {
return e.submit(task, result);
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return e.invokeAll(tasks);
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
return e.invokeAll(tasks, timeout, unit);
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
return e.invokeAny(tasks);
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return e.invokeAny(tasks, timeout, unit);
}
}
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
protected void finalize() {
super.shutdown();
}
}
/**
* A wrapper class that exposes only the ScheduledExecutorService
* methods of a ScheduledExecutorService implementation.
*/
static class DelegatedScheduledExecutorService
extends DelegatedExecutorService
implements ScheduledExecutorService {
private final ScheduledExecutorService e;
DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
super(executor);
e = executor;
}
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return e.schedule(command, delay, unit);
}
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return e.schedule(callable, delay, unit);
}
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return e.scheduleAtFixedRate(command, initialDelay, period, unit);
}
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
}
}
/** Cannot instantiate. */
private Executors() {}
}
2.6.1 线程池的创建与执行目标提交
- 通过 Executors 工厂类创建一个线程池,一个简单的示例如下:
//创建一个包含三个线程的线程池
private static ExecutorService pool = Executors.newFixedThreadPool(3);
工厂类Executors的newFixedThreadPool(int threads)方法创建了一个线程池,所创建的线程池的类型为ExecutorService。
工厂类的newFixedThreadPool(int threads)方法用于创建包含一个固定数目的线程池。ExecutorService是Java提供的一个线程池接口,每次我们在异步执行target目标任务的时候,可以通过ExecutorService线程池实例去提交或者执行。
ExecutorService实例负责对池中的线程进行管理和调度,并且可以有效控制最大并发线程数,提高系统资源的使用率,同时提供定时执行、定频执行、单线程、并发数控制等功能。
向ExecutorService线程池提交异步执行target日标任务的常用方法有:
//方法一:执行一个 Runnable类型的target执行目标实例,无返回
void execute(Runnable command);
//方法二:提交一个 Callable类型的target执行目标实例,返回一个Future异步任务实例
<T> Future<T> submit(Callable<T>task);
//方法三:提交一个 Runnable类型的target执行目标实例,返回一个Future异步任务实例
Future<?>submit(Runnable task);
2.6.2 线程池的使用
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个包含三个线程的线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(new DemoThread()); //执行线程实例
//执行Runnable执行目标实例
pool.execute(new Runnable() {
@Override
public void run() {
for (int j = 1; j < MAX_TURN; j++) {
// TODO
}
}
});
//提交Callable 执行目标实例
Future future = pool.submit(new ReturnableTask());
Long result = (Long) future.get();
System.out.println(("异步任务的执行结果为:" + result);
}
static class DemoThread implements Runnable {
@Override
public void run() {
for (int j = 1; j < MAX_TURN; j++) {
// TODO
}
}
}
public static final int MAX_TURN = 5;
public static final int COMPUTE_TIMES = 100000000;
static class ReturnableTask implements Callable<Long> {
//返回并发执行的时间
public Long call() throws Exception {
long startTime = System.currentTimeMillis();
// TODO
long used = System.currentTimeMillis() - startTime;
return used;
}
}
}
2.6.3 submit 和 execute区别
- 接收的参数不一样
submit()可以接受两种入参:- 无返回值的Runnable类型的target执行目标实例。
- 有返回值Callable类型的target执行目标实例。
- execute()仅仅接收无返回值的target执行目标实例,或者无返回值的Thread实例。
- submit()有返回值,而execute()没有
- submit()方法在提交异步target执行目标之后会返回Future异步任务实例,以对target的异步执行过程进行控制,比如取消执行、获取结果等。
- execute()没有任何返回,target执行目标实例在执行之后没有办法对其异步执行过程进行控制,只能任其执行,直到其执行结束。