关于Java中Runnable和Callable接口的区别和javarunnable和callable区别的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于androidcallable与r
关于Java中Runnable和Callable接口的区别和java runnable和callable区别的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于android callable与runnable的区别、Callable,Runnable的区别及用法、callable和runnable的区别、Java Callable接口、Runable接口、Future接口等相关知识的信息别忘了在本站进行查找喔。
本文目录一览:- Java中Runnable和Callable接口的区别(java runnable和callable区别)
- android callable与runnable的区别
- Callable,Runnable的区别及用法
- callable和runnable的区别
- Java Callable接口、Runable接口、Future接口
Java中Runnable和Callable接口的区别(java runnable和callable区别)
Runnable
在 Java 中设计并发线程时使用和接口有什么区别Callable
,为什么要选择一个而不是另一个?
答案1
小编典典请参阅此处的说明。
Callable 接口与 Runnable 类似,两者都是为实例可能由另一个线程执行的类设计的。 但是,Runnable
不返回结果,也不能抛出检查异常。
android callable与runnable的区别
编写多线程程序是为了实现多任务的并发执行,使用线程或者线程池,Thread,ExcutorService.线程或线程池会通过Callbale或者Runnable的对象实现具体线程的执行内容。
Runnable和Callable的区别是,
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
1、通过实现Runnable接口来创建Thread线程:
步骤1:创建实现Runnable接口的类:
class SomeRunnable implements Runnable
{
public void run()
{
//do something here
}
}
步骤2:创建一个类对象:
Runnable oneRunnable = new SomeRunnable();
步骤3:由Runnable创建一个Thread对象:
Thread oneThread = new Thread(oneRunnable);
步骤4:启动线程:
oneThread.start();
至此,一个线程就创建完成了。
注释:线程的执行流程很简单,当执行代码oneThread.start();时,就会执行oneRunnable对象中的void run();方法,
该方法执行完成后,线程就消亡了。
2、与方法1类似,通过实现Callable接口来创建Thread线程:其中,Callable接口(也只有一个方法)定义如下:
public interface Callable<V>
{
V call() throws Exception;
}
步骤1:创建实现Callable接口的类SomeCallable<Integer>(略);
步骤2:创建一个类对象:
Callable<Integer> oneCallable = new SomeCallable<Integer>();
步骤3:由Callable<Integer>创建一个FutureTask<Integer>对象:
FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
注释:FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口。
步骤4:由FutureTask<Integer>创建一个Thread对象:
Thread oneThread = new Thread(oneTask);
步骤5:启动线程:
oneThread.start();
至此,一个线程就创建完成了。
3、通过继承Thread类来创建一个线程:
步骤1:定义一个继承Thread类的子类:
class SomeThead extends Thraad
{
public void run()
{
//do something here
}
}
步骤2:构造子类的一个对象:
SomeThread oneThread = new SomeThread();
步骤3:启动线程:
oneThread.start();
至此,一个线程就创建完成了。
注释:这种创建线程的方法不够好,主要是因为其涉及运行机制问题,影响程序性能。
4、通过线程池来创建线程:
步骤1:创建线程池:
ExecutorService pool = Executors.newCachedThreadPool();
步骤2:通过Runnable对象或Callable对象将任务提交给ExecutorService对象:
Future<Integer> submit(Callable<Integer> task);
注释:Future是一个接口,它的定义如下:
public interface Future<T>
{
V get() throws ...;
V get(long timeout, TimeUnit unit) throws ...;
void cancle(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();
}
至此,一个线程就创建完成了。
注释:线程池需调用shutdown();方法来关闭线程。
5、通过事件分配线程直接使用程序中的原有线程:
使用方法:
直接调用EventQueue类的静态方法invokeLater():
EventQueue.invokeLater(oneRunnable);
注释:调用EventQueue.invokeLater(oneRunnable);会直接执行oneRunnable对象中的run()方法
原文:http://murielily.blog.163.com/blog/static/134260649201131215237637/
Callable,Runnable的区别及用法
编写多线程程序一般有三种方法,Thread,Runnable,Callable.
Runnable和Callable的区别是:
(1)Callable规定的方法是call(),Runnable规定的方法是run()。其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
(3)call方法可以抛出异常,run方法不可以
(4)运行Callable任务可以拿到一个Future对象,c表示异步计算的结果。
Future 提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如果线程没有执行完,Future.get()方法可能会阻塞当前线程的执行;如果线程出现异常,Future.get()会throws InterruptedException或者ExecutionException;如果线程已经取消,会跑出CancellationException。取消由cancel 方法来执行。isDone确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明Future<?>
形式类型,并返回 null 作为底层任务的结果。
/**
* 通过简单的测试程序来试验Runnable、Callable通过Executor来调度的时候与Future的关系
*/
package com.hadoop.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Future; public class RunnableAndCallable2Future { public static void main(String[] args) { // 创建一个执行任务的服务 ExecutorService executor = Executors.newFixedThreadPool(3); try { //1.Runnable通过Future返回结果为空 //创建一个Runnable,来调度,等待任务执行完毕,取得返回结果 Future<?> runnable1 = executor.submit(new Runnable() { @Override public void run() { System.out.println("runnable1 running."); } }); System.out.println("Runnable1:" + runnable1.get()); // 2.Callable通过Future能返回结果 //提交并执行任务,任务启动时返回了一个 Future对象, // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作 Future<String> future1 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { // TODO Auto-generated method stub return "result=task1"; } }); // 获得任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行 System.out.println("task1: " + future1.get()); //3. 对Callable调用cancel可以对对该任务进行中断 //提交并执行任务,任务启动时返回了一个 Future对象, // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作 Future<String> future2 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { try { while (true) { System.out.println("task2 running."); Thread.sleep(50); } } catch (InterruptedException e) { System.out.println("Interrupted task2."); } return "task2=false"; } }); // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环 Thread.sleep(10); System.out.println("task2 cancel: " + future2.cancel(true)); // 4.用Callable时抛出异常则Future什么也取不到了 // 获取第三个任务的输出,因为执行第三个任务会引起异常 // 所以下面的语句将引起异常的抛出 Future<String> future3 = executor.submit(new Callable<String>() { @Override public String call() throws Exception { throw new Exception("task3 throw exception!"); } }); System.out.println("task3: " + future3.get()); } catch (Exception e) { System.out.println(e.toString()); } // 停止任务执行服务 executor.shutdownNow(); } }
执行结果如下:
runnable1 running.
Runnable1:null
task1: result=task1
task2 running.
task2 cancel: true
Interrupted task2.
java.util.concurrent.ExecutionException: java.lang.Exception: Bad flag value!
FutureTask则是一个RunnableFuture,即实现了Runnbale又实现了Futrue这两个接口,另外它还可以包装Runnable和Callable,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
public class FutureTaskTest {
/** * @param args */ public static void main(String[] args) { Callable<String> task = new Callable<String>() { public String call() { System.out.println("Sleep start."); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("Sleep end."); return "time=" + System.currentTimeMillis(); } }; //直接使用Thread的方式执行 FutureTask<String> ft = new FutureTask<String>(task); Thread t = new Thread(ft); t.start(); try { System.out.println("waiting execute result"); System.out.println("result = " + ft.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } //使用Executors来执行 System.out.println("========="); FutureTask<String> ft2 = new FutureTask<String>(task); Executors.newSingleThreadExecutor().submit(ft2); try { System.out.println("waiting execute result"); System.out.println("result = " + ft2.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
执行结果如下:
waiting execute result
Sleep start.
Sleep end.
result = time=1370844662537
=========
waiting execute result
Sleep start.
Sleep end.
result = time=1370844672542
callable和runnable的区别
Runnable接口源码
@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();
}
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了 Runnable。激活的意思是说某个线程已启动并且尚未停止。
此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,
就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,
而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。
Callable接口源码
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;
}
返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
Executors 类包含一些从其他普通形式转换成 Callable 类的实用方法。
区别:
- callable可以抛异常, runnable不能
- callable可以有返回值, runnable不能
相同点:
- 两者都是接口;
- 两者都可用来编写多线程程序;
- 两者都需要调用Thread.start()启动线程;
Java Callable接口、Runable接口、Future接口
1. Callable与Runable区别
Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理。Thread类、Runnable接口和Java内存管理模型使得多线程编程简单直接。
但Thread类和Runnable接口都不允许声明检查型异常,也不能定义返回值。没有返回值这点稍微有点麻烦。不能声明抛出检查型异常则更麻烦一些。
public void run()方法契约意味着你必须捕获并处理检查型异常。即使你小心地保存了异常信息(在捕获异常时)以便稍后检查,但也不能保证这个类(Runnable对象)的所有使用者都读取异常信息。
你也可以修改Runnable实现的getter,让它们都能抛出任务执行中的异常。但这种方法除了繁琐也不是十分安全可靠,你不能强迫使用者调用这些方法,程序员很可能会调用join()方法等待线程结束然后就不管了。
但是现在不用担心了,以上的问题终于在1.5中解决了。Callable接口和Future接口的引入以及他们对线程池的支持优雅地解决了这两个问题。
不管用哪种方式创建线程,其本质都是Callable接口与Runable接口。两者都是可被其它线程执行的任务!!区别是:

(1)Callable规定的方法是call(),而Runnable规定的方法是run()。
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call()方法可抛出异常,而run()方法是不能抛出异常的。
(4)运行Callable任务可拿到一个Future对象。

2.Future
如上所说,Callable任务返回Future对象。即:Callable和Future一个产生结果,一个拿到结果。
Future 表示异步计算的结果。Future接口中有如下方法:
- boolean cancel(boolean mayInterruptIfRunning)
取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
- boolean isCancelled()
任务是否已经取消,任务正常完成前将其取消,则返回 true
- boolean isDone()
任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
- V get()
等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
- V get(long timeout, TimeUnit unit)
同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException
Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果。也可以设置任务执行的超时时间,这个设置超时的方法就是实现Java程序执行超时的关键。
所以,如果需要设定代码执行的最长时间,即超时,可以用Java线程池ExecutorService类配合Future接口来实现。
三个简单的小例子,体会一下:

package com.zyf.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class FutureGetTimeOut1 {
public static void main(String[] args){
int timeout = 2;
ExecutorService executor = Executors.newSingleThreadExecutor();
Boolean result = false;
Future<Boolean> future = executor.submit(new TaskThread("发送请求"));//将任务提交给线程池
try {
result = future.get(timeout, TimeUnit.SECONDS);
// result = future.get(timeout, TimeUnit.MILLISECONDS); //1
System.out.println("发送请求任务的返回结果: "+result); //2
} catch (InterruptedException e) {
System.out.println("线程中断出错。");
future.cancel(true);// 中断执行此任务的线程
} catch (ExecutionException e) {
System.out.println("线程服务出错。");
future.cancel(true);
} catch (TimeoutException e) {// 超时异常
System.out.println("超时。");
future.cancel(true);
}finally{
System.out.println("线程服务关闭。");
executor.shutdown();
}
}
static class TaskThread implements Callable<Boolean> {
private String t;
public TaskThread(String temp){
this.t= temp;
}
public Boolean call() {
//for用于模拟超时
for(int i=0;i<999999999;i++){
if(i==999999998){
System.out.println(t+"成功!");
}
if (Thread.interrupted()){ //很重要
return false;
}
}
System.out.println("继续执行..........");
return true;
}
}
}


package com.zyf.Future;
import java.util.concurrent.*;
public class FutureGetTimeOut2 {
public static void main(String[] args) {
final ExecutorService service = Executors.newFixedThreadPool(1);
TaskThread taskThread = new TaskThread();
System.out.println("提交任务...begin");
Future<Object> taskFuture = service.submit(taskThread);
System.out.println("提交任务...end");
try {
Object re = taskFuture.get(60000, TimeUnit.MILLISECONDS);// 超时设置
System.out.println(re);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
System.out.println("超时 取消任务");
taskFuture.cancel(true);
System.out.println("超时 取消任务OK");
} finally {
service.shutdown();
}
}
}
class TaskThread implements Callable<Object> {
public Object call() throws Exception {
String result = "空结果";
try {
System.out.println("任务开始....");
//修改sleep 的值测试超时
Thread.sleep(500);
result = "正确结果";
System.out.println("任务结束....");
} catch (Exception e) {
System.out.println("Task is interrupted!");
}
return result;
}
}


package com.zyf.Future;
import java.util.concurrent.*;
class MyCallable implements Callable<Object> {
private int flag = 0;
public MyCallable(int flag) {
this.flag = flag;
}
public String call() throws Exception {
if (this.flag == 0) {
return "flag = 0";
}
if (this.flag == 1) {
try {
while (true) {
System.out.println("looping.");
Thread.sleep(2000);
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
return "false";
} else {
throw new Exception("Bad flag value!");
}
}
}
public class FutureGetBlock {
public static void main(String[] args) {
// 定义3个Callable类型的任务
MyCallable task1 = new MyCallable(0);
MyCallable task2 = new MyCallable(1);
MyCallable task3 = new MyCallable(2);
// 创建一个执行任务的服务
ExecutorService es = Executors.newFixedThreadPool(3);
try {
// 提交并执行任务,任务启动时返回了一个Future对象,
// 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
Future<?> future1 = es.submit(task1);
// 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
System.out.println("task1: " + future1.get());
Future<?> future2 = es.submit(task2);
// 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
Thread.sleep(5000);
System.out.println("task2 cancel: " + future2.cancel(true));
// 获取第三个任务的输出,因为执行第三个任务会引起异常
// 所以下面的语句将引起异常的抛出
Future<?> future3 = es.submit(task3);
System.out.println("task3: " + future3.get());
} catch (Exception e) {
System.out.println(e.toString());
}
// 停止任务执行服务
es.shutdownNow();
}
}

3. Future实现类
3.1 FutureTask
FutureTask是一个RunnableFuture<V>,而RunnableFuture实现了Runnbale又实现了Futrue<V>这两个接口,

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

另外它还可以包装Runnable和Callable<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) {
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);
}
/**
* 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;
}
}

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。见下面两个例子:

package com.zyf.Future;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureTaskDemo {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
FutureTask<Integer> future = new FutureTask<Integer>(callable);
new Thread(future).start();
try {
Thread.sleep(1000);// 可能做一些事情
int result = future.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}


package com.zyf.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class FutureTaskDemo2 {
static ExecutorService mExecutor = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
futureDemo();
}
static void futureDemo() {
try {
/**
* 提交runnable则没有返回值, future没有数据
*/
Future<?> future = mExecutor.submit(new Runnable() {
@Override
public void run() {
fibc(20);
}
});
System.out.println("future result from runnable : " + future.get());
/**
* 提交Callable, 有返回值, future中能够获取返回值
*/
Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return fibc(20);
}
});
System.out.println("future result from callable : " + result2.get());
/**
* FutureTask则是一个RunnableFuture<V>,即实现了Runnbale又实现了Futrue<V>这两个接口,
* 另外它还可以包装Runnable(实际上会转换为Callable)和Callable
* <V>,所以一般来讲是一个符合体了,它可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行
* ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。
*/
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return fibc(20);
}
});
// 提交futureTask
mExecutor.submit(futureTask);
System.out.println("future result from futureTask : " + futureTask.get());
mExecutor.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
/**
* 效率底下的斐波那契数列, 耗时的操作
*
* @param num
* @return
*/
static int fibc(int num) {
if (num == 0) {
return 0;
}
if (num == 1) {
return 1;
}
return fibc(num - 1) + fibc(num - 2);
}
}

如果要执行多个带返回值的任务,并取得多个返回值,两种方法:
1.先创建一个装Future类型的集合,用Executor提交的任务返回值添加到集合中,最后便利集合取出数据。
这时候,submit的task不一定是按照加入自己维护的list顺序完成的。从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住。
如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
所以jdk1.8增加了Future接口的另外一个实现类CompletionService
2.CompletionService相当于Executor加上BlockingQueue,使用场景为当子线程并发了一系列的任务以后,主线程需要实时地取回子线程任务的返回值并同时顺序地处理这些返回值,谁先返回就先处理谁。
而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。
所以,先完成的必定先被取出。这样就减少了不必要的等待时间。
from: https://www.cnblogs.com/felixzh/p/6044371.html
今天关于Java中Runnable和Callable接口的区别和java runnable和callable区别的讲解已经结束,谢谢您的阅读,如果想了解更多关于android callable与runnable的区别、Callable,Runnable的区别及用法、callable和runnable的区别、Java Callable接口、Runable接口、Future接口的相关知识,请在本站搜索。
本文标签: