目前還沒有實操過從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");}
}
附:虛擬線程
可以復習下虛擬內存。
首先是"虛"的,并不是實際那么多內存,但是給你的感覺就是很多內存。怎么做到的,做一些虛擬的映射,然后調換更新,給你錯覺就可以了。
看看虛擬內存的關鍵問題?
- 地址映射問題:在訪問主存時把虛地址變為主存物理地址(這一過程稱為內地址變換);在訪問輔存時把虛地址變成輔存的物理地址(這一過程稱為外地址變換),以便換頁。此外還要解決主存分配、存儲保護與程序再定位等問題
- 調度問題:決定哪些程序和數據應被調入主存
- 替換問題:決定哪些程序和數據應被調出主存
- 更新問題:確保主存與輔存的一致性
回到虛擬線程。
一樣的道理,設計一種輕量級的調度資源。讓多個去綁定一個線程,營造出很多線程的感覺,但是不是真正的內核級別線程。只是一種用異步執行框架設計出來的執行單元。
來看看虛擬線程的關鍵特性
- 輕量級:虛擬線程的創建和銷毀成本非常低,通常只需要幾十個字節的內存。
- 自動上下文管理:虛擬線程會自動管理其上下文(例如,局部變量、異常處理器等),使得開發者不需要手動管理這些上下文。
- 易于使用:通過異步編程模型,虛擬線程使得編寫異步和非阻塞代碼變得更加簡單和直觀。