-
批量思想:批量操作数据库,这个很好理解,我们在循环插入场景的接口中,可以在批处理执行完成后一次性插入或更新数据库,避免多次IO。 批处理案例,创建一个文件夹并将一些文件移动到该文件夹中:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
public class BatchExample {
public static void main(String[] args) {
// 设置文件夹路径和文件扩展名
String folderPath = "C:/Test";
String extension = "txt";
// 创建文件夹
File folder = new File(folderPath);
if (!folder.exists()) {
folder.mkdir();
}
// 移动具有指定文件扩展名的文件到文件夹中
File[] files = new File(".").listFiles((dir, name) -> name.toLowerCase().endsWith("." + extension));
if (files != null) {
for (File file : files) {
try {
Path source = file.toPath();
Path destination = new File(folderPath, file.getName()).toPath();
Files.move(source, destination, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("操作完成");
}
}
**
这段代码使用Java的File和Files类来创建文件夹和移动文件。首先,它设置了要创建的文件夹路径和文件的扩展名。然后,它通过File类创建了指定路径下的文件夹。接下来,使用File类的listFiles()方法获取当前目录下指定扩展名的文件列表。然后,使用Files类的move()方法将每个文件移动到刚创建的文件夹中。最后,输出一条消息表示操作完成。
2.异步处理
异步思想:针对耗时比较长且不是结果必须的逻辑,我们可以考虑放到异步执行,这样能降低接口耗时。
异步处理的案例,演示了如何使用CompletableFuture进行异步处理:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class AsyncExample {
public static void main(String[] args) {
// 启动异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
// 模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello, world!";
});
// 异步任务完成后的回调处理
future.thenAccept(result -> {
System.out.println("异步任务完成,结果为:" + result);
});
// 主线程继续执行其他操作
System.out.println("正在执行其他操作...");
try {
// 阻塞等待异步任务完成
future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
**
上述代码中,使用CompletableFuture.supplyAsync()方法创建了一个异步任务,在任务中进行耗时操作并返回结果。然后,使用thenAccept()方法设置了异步任务完成后的回调处理,输出任务结果。接着,主线程继续执行其他操作,并通过future.get()方法阻塞等待异步任务的完成
3.空间换时间
一个很好理解的空间换时间 的例子是合理使用缓存,针对一些频繁使用且不频繁变更的数据,可以提前缓存起来,需要时直接查缓存,避免频繁地查询数据库或者重复计算。
需要注意的事,这里用了合理二字,因为空间换时间也是一把双刃剑,需要综合考虑你的使用场景,毕竟缓存带来的数据一致性问题也挺令人头疼。
这里的缓存可以是R2M,也可以是本地缓存、memcached,或者Map。
4.预处理
也就是预取思想,就是提前要把查询的数据,提前计算好,放入缓存或者表中的某个字段,用的时候会大幅提高接口性能。跟上面那个例子很像,但是关注点不同。
5.池化思想
我们都用过数据库连接池,线程池等,这就是池思想的体现,它们解决的问题就是避免重复创建对象或创建连接,可以重复利用,避免不必要的损耗,毕竟创建销毁也会占用时间。
池化思想的案例代码,它演示了如何使用对象池来重复使用对象,避免频繁创建和销毁对象的开销:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ObjectPool<T> {
private BlockingQueue<T> objectPool;
public ObjectPool(int poolSize) {
objectPool = new ArrayBlockingQueue<>(poolSize);
for (int i = 0; i < poolSize; i++) {
objectPool.offer(createObject());
}
}
public T borrowObject() {
try {
return objectPool.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
public void returnObject(T object) {
objectPool.offer(object);
}
private T createObject() {
// 在这里进行对象的创建逻辑
// 返回一个新的对象实例
return null;
}
// 示例代码,模拟使用对象池的场景
public static void main(String[] args) {
ObjectPool<MyObject> objectPool = new ObjectPool<>(10);
// 借用对象
MyObject obj1 = objectPool.borrowObject();
MyObject obj2 = objectPool.borrowObject();
// 使用对象
if (obj1 != null) {
obj1.doSomething();
}
if (obj2 != null) {
obj2.doSomething();
}
// 归还对象
objectPool.returnObject(obj1);
objectPool.returnObject(obj2);
// 再次借用对象,此时应该是重复利用之前归还的对象
MyObject obj3 = objectPool.borrowObject();
MyObject obj4 = objectPool.borrowObject();
// 使用对象
if (obj3 != null) {
obj3.doSomething();
}
if (obj4 != null) {
obj4.doSomething();
}
}
private static class MyObject {
public void doSomething() {
System.out.println("Doing something...");
}
}
}
**
在上述代码中,我们定义了一个名为ObjectPool的泛型类。它包含了一个阻塞队列objectPool来存储对象实例。在构造函数中,我们初始化了一个固定大小的对象池,并通过createObject()方法创建了一组对象实例放入池中。
borrowObject()方法从对象池中借用对象,它从队列中取出一个对象实例,并在需要时阻塞等待可用对象。
returnObject()方法用于将对象归还到对象池中,将对象实例放回队列中,以备后续重复使用。
main()方法是一个示例场景,展示了如何使用对象池借用和归还对象。在示例中,我们借用了两个对象obj1和obj2,使用完毕后将它们归还到对象池中。然后,再次借用对象时,应该是重复利用之前归还的对象。
代码中的createObject()方法和MyObject类都需要根据实际需求来具体实现。createObject()方法用于创建对象的逻辑,可以根据需要添加新的实例化逻辑。MyObject是一个示例对象类,具体需要根据实际业务来定义和实现。
6.串行改并行
串行就是,当前执行逻辑必须等上一个执行逻辑结束之后才执行,并行就是两个执行逻辑互不干扰,所以并行相对来说就比较节省时间,当然是建立在没有结果参数依赖的前提下。