了解Java21
目前还没有实操过从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";};}
}
类型推断switch例子
interface Go {
}class Bus implements Go {public void out() {System.out.println("by bus");}
}class Car implements Go {public void drive() {System.out.println("drive car");}
}public class MainStr {public static void main(String[] args) {Go go1 = new Bus();outGo(go1);Go go2 = new Car();outGo(go2);}public static void outGo(Go go) {switch (go) {case Bus bus -> bus.out();case Car car -> car.drive();default -> throw new IllegalStateException("Unexpected value: " + go);}}}
虚拟线程
测试如下 确实是虚拟线程快一些。(例子场景是密集的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");}
}
附:虚拟线程
可以复习下虚拟内存。
首先是"虚"的,并不是实际那么多内存,但是给你的感觉就是很多内存。怎么做到的,做一些虚拟的映射,然后调换更新,给你错觉就可以了。
看看虚拟内存的关键问题?
- 地址映射问题:在访问主存时把虚地址变为主存物理地址(这一过程称为内地址变换);在访问辅存时把虚地址变成辅存的物理地址(这一过程称为外地址变换),以便换页。此外还要解决主存分配、存储保护与程序再定位等问题
- 调度问题:决定哪些程序和数据应被调入主存
- 替换问题:决定哪些程序和数据应被调出主存
- 更新问题:确保主存与辅存的一致性
回到虚拟线程。
一样的道理,设计一种轻量级的调度资源。让多个去绑定一个线程,营造出很多线程的感觉,但是不是真正的内核级别线程。只是一种用异步执行框架设计出来的执行单元。
来看看虚拟线程的关键特性
- 轻量级:虚拟线程的创建和销毁成本非常低,通常只需要几十个字节的内存。
- 自动上下文管理:虚拟线程会自动管理其上下文(例如,局部变量、异常处理器等),使得开发者不需要手动管理这些上下文。
- 易于使用:通过异步编程模型,虚拟线程使得编写异步和非阻塞代码变得更加简单和直观。