目前还没有实操过从java8/java11直接到java17,java21。
先储备下知识点,写一些简单例子,以便后续的实操。
一些新特性(java8之后的)
var变量
和前端js定义变量一样了,var搞定
public static void main(String[] args) {
var str = "xxx";
var a = new Object();
var num = 123;
System.out.println(num);
System.out.println(str.getClass().getName());
System.out.println(a.getClass().getName());
}
当然有限制:局部变量,for循环引用等地方
多行文本字符串
public static void main(String[] args) {
String s1 = "第一行\n第二行\n第三行";
System.out.println(s1);
System.out.println(s1.length());
System.out.println("------");
String s2 = """
第一行
第二行
第三行""";
System.out.println(s2);
System.out.println(s2.length());
}
效果一样
简单好用的switch case
public class MainSwitch {
public static void main(String[] args) {
MainSwitch main = new MainSwitch();
System.out.println(main.switchTest("one"));
System.out.println(main.switchTest("two"));
}
public String switchTest(String str) {
return switch (str){
case "one" -> "1";
case "two" -> "2";
default -> "0";
};
}
}
虚拟线程
测试如下 确实是虚拟线程快一些。(例子场景是密集的IO请求)
想象多线程为什么慢? 内核开辟资源,多线程的切换,上下文的切换,线程阻塞等待IO…
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class VirtualThread {
public static void main(String[] args) throws Exception{
testThread();
testVirtualThread();
}
public static void testVirtualThread() throws Exception {
HttpClient client = HttpClient.newHttpClient();
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // 每个任务使用虚拟线程
long startTime = System.currentTimeMillis();
IntStream.range(0, 100).forEach(i -> {
executor.submit(() -> {
try {
HttpRequest request = HttpRequest.newBuilder()
.version(HttpClient.Version.HTTP_2)
.uri(URI.create("http://localhost:8080/health"))
.build();
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
e.printStackTrace();
}
});
});
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
System.out.println("Java 21 耗时: " + (System.currentTimeMillis() - startTime) + "ms");
}
public static void testThread() throws Exception {
HttpClient client = HttpClient.newHttpClient();
ExecutorService executor = Executors.newFixedThreadPool(10); // 限制线程池大小
long startTime = System.currentTimeMillis();
IntStream.range(0, 100).forEach(i -> {
executor.submit(() -> {
try {
HttpRequest request = HttpRequest.newBuilder()
.version(HttpClient.Version.HTTP_2)
.uri(URI.create("http://localhost:8080/health"))
.build();
client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
e.printStackTrace();
}
});
});
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
System.out.println("Java 8 耗时: " + (System.currentTimeMillis() - startTime) + "ms");
}
}
附:虚拟线程
可以复习下虚拟内存。
首先是"虚"的,并不是实际那么多内存,但是给你的感觉就是很多内存。怎么做到的,做一些虚拟的映射,然后调换更新,给你错觉就可以了。
看看虚拟内存的关键问题?
- 地址映射问题:在访问主存时把虚地址变为主存物理地址(这一过程称为内地址变换);在访问辅存时把虚地址变成辅存的物理地址(这一过程称为外地址变换),以便换页。此外还要解决主存分配、存储保护与程序再定位等问题
- 调度问题:决定哪些程序和数据应被调入主存
- 替换问题:决定哪些程序和数据应被调出主存
- 更新问题:确保主存与辅存的一致性
回到虚拟线程。
一样的道理,设计一种轻量级的调度资源。让多个去绑定一个线程,营造出很多线程的感觉,但是不是真正的内核级别线程。只是一种用异步执行框架设计出来的执行单元。
来看看虚拟线程的关键特性
- 轻量级:虚拟线程的创建和销毁成本非常低,通常只需要几十个字节的内存。
- 自动上下文管理:虚拟线程会自动管理其上下文(例如,局部变量、异常处理器等),使得开发者不需要手动管理这些上下文。
- 易于使用:通过异步编程模型,虚拟线程使得编写异步和非阻塞代码变得更加简单和直观。