.
一、合理配置线程池
1、IO密集型
- 任务需要大量的IO阻塞,要解决阻塞问题,可以使用多线程技术
- 为了保证CPU的运算能力,不会浪费资源,配置线程数=2*CPU核数
2、CPU密集型
- 该任务执行的时候不会产生大量的IO阻塞,CPU运行的时候速度特别快
- 配置线程数=CPU核数
二、Callable
- 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。
- 然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。
- 我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。
- 而这样要获取run方法的执行结果,必须要执行完毕后才能获取到结果,整个程序是阻塞的
- 不过,Java中,也提供了使用Callable和Future来实现获取任务结果的操作
- Callable用来执行任务,产生结果,而Future用来获得结果
public class App {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
Future<String> submit = newCachedThreadPool.submit(new TaskCallable());
System.out.println("1.主线程开始执行...");
String result = submit.get();
System.out.println("2.result:" + result);
}
}
class TaskCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("3.正在执行任务,需要等待五秒时间,执行任务开始");
Thread.sleep(5000);
System.out.println("4.正在执行任务,需要等待五秒时间,执行任务结束");
return "Done";
}
}
三、Future模式
- Future模式的核心在于:
- 去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑
A和B两个线程,如果A需要B的执行结果,那么这个A线程不需要等待B执行完毕后,才能拿到结果
使用Future模式可以先拿到一个未来的Future,等B有结果时再取真实的结果
四、手动实现future模式
- 源码执行分析
- 1、从main函数开始
FutureClient futureClient = new FutureClient();
执行 - 2、调用futureClient.request后,实例化了futureData对象
- 3、并且开启了一个线程,调用了realData的构造函数
- 4、而realData的构造函数执行了sleep=3000的操作
- 5、然后调用了futureData.setRedData(realData);获取数据后来唤醒线程
- 6、注意:main函数中的String result = request.getRequest();这个是在主线程执行的
- 执行了request.getRequest()的时候,此时还没有获取到数据,所以线程处于wait状态
- 1、从main函数开始
1、Data类
//公共data数据结果
public abstract class Data {
//返回线程执行结果
public abstract String getRequest();
}
2、RealData类
//获取真实数据
public class RealData extends Data{
private String requestData;
public RealData(String requestData){
System.out.println("正在使用data进行网络请求,data:"+ requestData + ",开始...");
try{
Thread.sleep(3000);
}catch (Exception e){
}
System.out.println("操作执行完毕...获取到结果");
//获取
this.requestData = "Done";
}
@Override
public String getRequest() {
return requestData;
}
}
3、FutureData类
//当有线程想要获取RealData的时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法
public class FutureData extends Data {
//读取结果
private boolean FLAG = false;
private RealData realData;
//读取data数据
public synchronized void setRedData(RealData realData){
//如果已经取到结果,直接返回
if(FLAG){
return;
}
//如果flag为false,没有获取到数据,传递realData对象
this.realData = realData;
FLAG = true;
notify();
}
@Override
public synchronized String getRequest(){
while (!FLAG){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.getRequest();
}
}
4、FutureClient
public class FutureClient {
//
public Data submit(String requestData){
final FutureData futureData = new FutureData();
new Thread(new Runnable() {
@Override
public void run() {
//阻塞
RealData realData = new RealData("60030");
futureData.setRedData(realData);
}
}).start();
return futureData;
}
}
5、Main函数
public class Main {
public static void main(String[] args) {
FutureClient futureClient = new FutureClient();
Data request = futureClient.request("123213");
System.out.println("main.数据发送成功.");
System.out.println("主线程执行其他任务");
String result = request.getRequest();
System.out.println("主线程获取result:" + result);
}
}
执行截图: