java中创建多线程是基于下面四种组件:Callable runnable ExecutorService的submit和execute方法 futureTask,这里简单介绍这些组件和创建线程的8种方式
submit---带返回值
提交值返回任务以执行,并返回代表任务待处理结果的Future。
Future> submit(Runnable task)
提交一个可运行的任务执行,并固定返回null
提交一个可运行的任务执行,并返回一个表示该任务的未来。
execute--不带返回值
void execute(Runnable command)
在将来的某个时间执行给定的命令。 该命令可以在一个新线程,一个合并的线程中或在调用线程中执行,由Executor实现。
FutureTask实现了Runnable接口和Future接口
FutureTask(Callable
创建一个 FutureTask ,它将在运行时执行给定的 Callable 。
FutureTask(Runnable runnable, V result)
创建一个 FutureTask ,将在运行时执行给定的 Runnable ,并安排 get将在成功完成后返回给定的结果。
Callable接口:
public interface Callable
V call() throws Exception;
}
Runnable接口:
public interface Runnable {
public abstract void run();
}
相同点:
两者都是接口;(废话)
两者都可用来编写多线程程序;
两者都需要调用Thread.start()启动线程;
不同点:
两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
没有返回值方式3种:
实现runnable接口--1种
继承Thread--1种
线程池:ExecutorService.execute(runnable)
有返回值方式5种
FutureTask实现的方式--2种
new Thread(new FutureTask(Runnable,result)).start()--固定返回值方式
new Thread(new FutureTask(callable)).start()--非固定返回值方式
线程池实现三种
ExecutorService.submit(runnable,result)----固定返回值方式
ExecutorService.submit(runnable)---固定返回值方式,且返回值为null
ExecutorService.submit(callable)---非固定返回值方式
说明:,其实submit底层也会用到execute,所以如果提交的任务不需要一个结果的话直接用execute()会提升很多性能。结论二:就是相当于说如果你传的任务是需要结果的,那你就使用你的类去继承Callable接口,然后告诉submit方法就行了,如果你只需要一个特定的结果,就把那个特定的结果告诉submit方法然后把你想要的特定结果也告诉他,它只是帮你完成以前使用Future模式的时候你自己需要做的那些步骤而已,如果你不需要一个结果,那么就老老实实使用execute,如果你需要的是一个空结果,那么submit(yourRunnable)与submit(yourRunnable,null)是等价的!
按返回值类型划分可以分为返回值为null(runnable1种),返回值固定(runnable2种),和返回值不固定(callable2种)
如果需要有返回值的多线程,要么借助futureTask,要么用submit的返回future方式,这样才有返回值
callable实现多线程,返回值是不定的
Runnable的有返回值一定是确定的
下面是创建线程的一些实例。
定义线程类实现Runnable接口,重写run()方法,线程类实例化,实例化线程类引用线程类的实例化,线程类调用start()方法(推荐使用实现接口、灵活)
class Runner inplements Runnable{
public void run(){
}
}
Runner runner=new Runner();
Thread thread=new Thread(runner);
thread.start();
定义一个Thread的子类,重写run()方法,子类实例化,然后调用start()方法
class Mythread extends thread{
public void run(){
}
}
Mythread mythread=new Mythread();
mythread.start();
/**
* 通过new Thread(new FutureTask(callable))开启线程
*/
private void callableFutureTaskThread() {
FutureTask futureTask = new FutureTask(new Callable() {
@Override
public String call() throws Exception {
System.out.println("通过new Thread(new FutureTask(callable))开启线程");
return "finish 通过new Thread(new FutureTask(callable))开启线程";
}
});
new Thread(futureTask).start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
FutureTask的经典使用方法,利用FutureTask和ExecutorService,可以用多线程的方式提交计算任务,主线程继续执行其他任务,当主线程需要子线程的计算结果时,在异步获取子线程的执行结果。
public class Caller implements Callable{
@Override
public Integer call() throws Exception {
int result = 0;
for(int i=0;i<10;i++){
result += i;
}
Thread.sleep(3000l);
return result;
}
public static void main(String[] args) {
ArrayList> arrayList = new ArrayList>();
ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i=0 ;i<5;i++){
FutureTask task = new FutureTask(new Caller());//callable需要用futuretask封装,然后调用线程池submit方法返回future
arrayList.add(task);
threadPool.execute(task);
threadPool.submit(task);
}
threadPool.shutdown();
System.out.println("main running ------");
while(!threadPool.isTerminated()){
}
System.out.println("main running after all task down ------");
int result=0;
for(FutureTask task : arrayList){
try {
result += task.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("result:"+result);
}
}
/**
* 通过 executorService.submit(callable)并且return一个Future开启线程
*/
private void executorServiceCallableFuture() {
ExecutorService executorService = Executors.newFixedThreadPool(5);//创建一个可重用固定线程数的线程池;
Future future = executorService.submit(new Callable() {
@Override
public String call() throws Exception {
System.out.println("通过 executorService.submit(callable)并且return一个Future开启线程");
return "finish 通过 executorService.submit(callable)并且return一个Future开启线程";
}
});
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
/**
* 通过 executorService.submit(runnable,T)并且return一个Future开启线程
*/
private void executorServiceRunnableFuture() {
ExecutorService executorService = Executors.newFixedThreadPool(5);//创建一个可重用固定线程数的线程池;
Future future = executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println("通过 executorService.submit(runnable,T)并且return一个Future开启线程");
}
},"finish 通过 executorService.submit(runnable,T)并且return一个Future开启线程");
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
调用 start() 方法是用来启动线程的,轮到该线程执行时,会自动调用 run();直接调用 run() 方法,无法达到启动多线程的目的,相当于主线程线性执行 Thread 对象的 run() 方法。
一个线程对线的 start() 方法只能调用一次,多次调用会抛出 java.lang.IllegalThreadStateException 异常;run() 方法没有限制。