前言:目前大部分操作系统都是以线程为CPU调度和分派基本单位。多线程在日常程序中运用的还是比较多的,潜在的我们web容器帮我们在http层面可以同时处理多个请求,这些可能多我们是无感的。平常的开发中,我们需要结合业务场景来合理运用多线程,例如大文件的IO操作,大量消息发送,都可以运用多线程来处理,充分利用多核CPU性能。
本文主要介绍2个方面:1:创建线程几种方式,包含Java8方式(建议使用,真的很方便);2.异步的callable接口简介。
一、创建线程的方式
- 继承Thread类创建线程
- 实现Runnable接口创建线程
- 使用Callable和Future创建线程
- 使用线程池
a.继承Thread类,重写run()
public class Test extends Thread {
@Override
public void run() {
System.out.println("hello,word!");
}
public static void main(String[] args) {
Test test = new Test();
test.start();
}
}
b.实现Runnable接口创建线程
public class Test implements Runnable {
@Override
public void run() {
System.out.println("hello,word!");
}
public static void main(String[] args) {
Thread thread = new Thread(new Test());
thread.start();
}
}
//Java 8 lambda写法
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(
() -> System.out.println("hello,word!"));
thread.start();
}
}
c.使用Callable和Future创建线程
public class Test implements Callable<String> {
@Override
public String call() throws Exception {
return "hello,word!";
}
public static void main(String[] args) {
Callable<String> test = new Test();
try {
FutureTask<String> futureTask = new FutureTask<>(test);
Thread thread = new Thread(futureTask);
thread.run();
System.out.println(futureTask.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
//java8 lambda匿名类写法
public class Test {
public static void main(String[] args) {
FutureTask<String> futureTask=new FutureTask<>(()->"hello,word!");
Thread thread = new Thread(futureTask);
thread.start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
d.使用线程池
public class Test {
public static void main(String[] args) {
FutureTask<String> futureTask=new FutureTask<>(()->"hello,word!");
ExecutorService service=Executors.newFixedThreadPool(2);
service.submit(futureTask);
try {
System.out.println( futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
二、Callable小说
Callable和Runnbale一样代表着任务,区别在于Callable有返回值并且可以抛出异常!Callable是一种可以返回结果的任务,这是它与Runnable的区别,但是通过适配器模式可以使Runnable与Callable类似。Future代表了一个异步的计算,可以从中得到计算结果、查看计算状态,其实现FutureTask可以被提交给Executor执行,多个线程可以从中得到计算结果。Callable和Future是配合使用的,当从Future中get结果时,如果结果还没被计算出来,那么线程将会被挂起,FutureTak内部使用一个单链表维持等待的线程;当计算结果出来后,将会对等待线程解除挂起,等待线程就都可以得到计算结果了。
Future接口、FutureTask类
Future是一个接口,代表了一个异步计算的结果。接口中的方法用来检查计算是否完成、等待完成和得到计算的结果。当计算完成后,只能通过get()方法得到结果,get方法会阻塞直到结果准备好了。如果想取消,那么调用cancel()方法。其他方法用于确定任务是正常完成还是取消了。一旦计算完成了,那么这个计算就不能被取消。
FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask是一个提供异步计算的结果的任务。 FutureTask可以用来包装Callable或者Runnbale对象。因为FutureTask实现了Runnable接口,所以FutureTask也可以被提交给Executor。
//FutureTask 2构造方法
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
}