Đề Xuất 2/2023 # Tìm Hiểu Về Java 9 Features # Top 6 Like | Cuocthitainang2010.com

Đề Xuất 2/2023 # Tìm Hiểu Về Java 9 Features # Top 6 Like

Cập nhật nội dung chi tiết về Tìm Hiểu Về Java 9 Features mới nhất trên website Cuocthitainang2010.com. Hy vọng thông tin trong bài viết sẽ đáp ứng được nhu cầu ngoài mong đợi của bạn, chúng tôi sẽ làm việc thường xuyên để cập nhật nội dung mới nhằm giúp bạn nhận được thông tin nhanh chóng và chính xác nhất.

Điểm qua một số features chính mà Oracle đã phát triển cho Java 9, bao gồm Java programming, JVM, Tools và các libraries :

Platform Module System (Project Jigsaw)

Interface Private Methods

Try-With Resources

Anonymous Classes

@SafeVarargs Annotation

Collection Factory Methods

Process API Improvement

New Version-String Scheme

JShell: The Java Shell (REPL)

Process API Improvement

Control Panel

Stream API Improvement

Installer Enhancement for Microsoft windows and many more

Optional Class

– Interface Private Methods : Ở Java 8 ta đã có thể cung cấp các hàm implement trong interface bằng cách sử dụng hàm Default và Static method. Và ở Java 9, để tránh code bị dư thừa và tăng cường khả năng tái sử dụng, Oracle tiếp tục cung cấp private method và private static method trong interface. Ví dụ :

interface iValidation{ private Long connectToDB(){ } default boolean checkByDefault(Form form){ connectToDB(); } public boolean check(Form form); public void print result(); } public class ValidationClass implements iValidation { public boolean check(Form form) { } public static void main(String[] args) { ValidationClass v = new ValidationClass(); v.check(new Form("abc", "xyz")); v.checkByDefault(new Form("abc", "xyz")); } }

– Try-With Resources : Cải thiện feature này từ Java 7.

Tránh việc viết nhiều các khối catch/finally block

Clean code, tăng tính dễ đọc

Không cần check null

Không cần phải kiểm tra xem resource có tham chiếu đến một đối tượng hay null(better Exception Handling)

Quản lý Resource tốt hơn

Tránh memory leakages

Ví dụ : Ở Java 7 hay 8

void test() throws IOException{ BufferedReader reader = new BufferedReader(new FileReader("journaldev.txt")); try (BufferedReader reader1 = reader) { System.out.println(reader1.readLine()); } }

Sau khi được nâng cấp ở Java 9

void test() throws IOException{ BufferedReader reader = new BufferedReader(new FileReader("journaldev.txt")); try (reader) { System.out.println(reader1.readLine()); } }

– Collection Factory Methods : Ở các phiên bản cũ, Java đã được hỗ trợ Generic cho các collection, nay ở Java 9 sẽ cung cấp thêm phương thức để ràng buộc số lượng của một collection(update feature đã có từ Java 7)

Đơn giản là Immutable(cố định) hoặc Unmodifiable(không thể thay đổi) một collection(Set, List, Map). Ở Java 7

list.add(“one”); list.add(“two”); list.add(“three”);

Ở Java 9, cách khai báo đã đơn giản hơn rất nhiều :

Kết quả :

– Optional Class : Là một container, dùng để thay thế cho null, hỗ trợ tốt hơn cho việc Exception handling, tránh lỗi NullPointerException.

– JShell: The Java Shell (REPL) : Tương tác với Java programming thông qua terminal thay vì 1 editor như Eclipse hay Intellij,…

Tăng khả năng chạy 1 chương trình Java, hoặc test

REPL (Read Evaluate Print Loop) tool

Một số ví dụ cơ bản :

Import : /import

| import java.io.* | import java.util.prefs.* | import java.util.regex.* | import java.util.stream.* | import java.sql.*

Debug, display giá trị các biến : /vars

| int $test1 = 5 | int $test1 = 5 | int $test3 = 25

Và còn rất nhiều feature ta có thể tương tác được với Java programming thông qua Jshell như :

Bắt các Exceptions một cách tự động, hiển thị thông tin như thường

Các khái niệm access modifier, modifier không có tác dụng. Duy chỉ có abstract modifier là cho phép(khi được khai báo trong class)

……

Stream API Improvement : Cải thiện Stream feature(Java 8), và thêm một số method mới :

takeWhile() : lấy element phù hợp với điều kiện được định nghĩa. Nếu fail là stop luôn

// Result : [ ]. Vì ngay ở element vị trí 0 không chia hết cho 2 rồi nên stop luôn System.out.println(list); System.out.println(list.getClass().getName());

dropWhile() : Ngược lại với takeWhile(), element nào phù hợp điều kiện thì bỏ qua, ko phù hợp thì được collect

// Result : [3, 4, 5, 6, 7, 8, 9, 10] . Bởi 2 element đầu map nên bỏ qua System.out.println(list);

iterate() : Duyệt qua từng element, gồm 3 tham số seed, hasNext and next.

To be continued

Tìm Hiểu Về Java Platform Independent

Chào mọi người, mình có bỏ chút ít thời gian để tìm hiểu về Java và đã hiểu thêm được một ít kiến thức về Java platform independent.

Việc đầu tiên của chúng ta khi bắt đầu học một ngôn ngữ bắt kì luôn là in ra câu “Hello world!”. Và sau khi in ra được câu “Hello world!”, chắc hẳn chúng ta luôn có cảm giác thỏa mãn đúng không nào.

Nhưng rất nhiều người trong chúng ta quên rằng, phần kết quả hiển thị trên màn hình cũng chỉ như là phần nổi của một tảng băng chìm mà thôi. Chúng ta cũng nên biết thêm chút ít về “phần chìm” của tảng băng, dù không cần chuyên sâu nhưng cũng đủ để trả lời thêm một vài câu hỏi hay tỏ ra nguy hiểm khi đi phỏng vấn phải không nào.

Trước tiên, câu hỏi đưa mình đến với việc tìm hiểu này là: “Tại sao Java source code có thể chạy được trên tất cả các hệ điều hành?”.

Và sau khi tìm hiểu trên Internet, mình đã biết được phần nào đó lý do, đó chính là nhờ có Java virtual machine. Vậy Java virtual machine là gì? Và vì sao nó lại giúp cho Java có thể chạy trên tất cả các hệ điều hành?

Java virtual machine (JVM) là một phần mềm dùng để thực thi các chương trình như một cổ máy thực sự. Các chương trình Java sử dụng chúng một cách trừu tượng và không trực tiếp truy cập vào hệ điều hành. Điều quan trọng ở đây, là JVM phụ thuộc vào mỗi hệ điều hành khác nhau. Vì vậy bạn cần phải cài đặt bản JVM tương ứng với hệ điều hành mà mình đang chạy.

Và JVM không thực thi trực tiếp các chương trình, mà sẽ thông qua một quá trình khác. Chương trình Java sẽ được biên dịch thành các bytecode bởi Java compiler. Sau đó, JVM mới phiên dịch bytecode để thực thi chương trình. Và đây là quy trình cụ thể hơn về việc thực thi một chương trình Java.

Một chương trình, hay đoạn code dù cho là được viết bằng ngôn ngữ lập trình gì, thì ngôn ngữ này cũng chỉ đang ở mức độ mà mỗi con người có thể đọc và hiểu (Đôi khi điều này cũng không đúng ). Nó có thể gồm các mệnh đề so sánh, tính toán hay các đoạn block, dù là gì thì máy vẫn không thể hiểu được.

Và để cho máy có thể hiểu được một chương trình, chúng cần được biên dịch thành ngôn ngữ dành cho máy. Và đây chính là vai trò của Java compiler và JVM. Đầu tiên, Java compiler sẽ biên dịch chương trình thành các bytecode. Vậy nhiệm vụ của Java compiler chính là chuyển đổi source code cho một chương trình khác từ ngôn ngữ lập trình sang ngôn ngữ có thể thực thi được. Và tiếp đến, output này có thể là một chuỗi lệnh có thể được thực thi trực tiếp bởi CPU hoặc nó cần thông qua một bước thông dịch nữa bởi JVM để có thể thực thi được.

Vậy tổng quan các bước để thực thi một chương trình Java được tóm tắt như sau:

Trước tiên Java compiler sẽ biên dịch mã nguồn, tạo ra các bytecode.

Và tiếp theo bytecode có thể sẽ được thực thi trực tiếp bởi CPU hoặc được phiên dịch thành các đoạn code có thể thực thi được bởi JVM.

Cuối cùng là chương trình được thực thi và cho ra kết quả cuối cùng.

Qua những gì mình đã trình bày ở trên, thì thực ra nếu không có Java compiler cũng như JVM không tương thích với hệ điều hành, thì việc thực thi các chương trình Java trên các hệ điều hành khác nhau là không thể. Chính việc có thể chạy trên mọi hệ điều hành, đã làm cho Java trở thành một nền tảng độc lập.

Tham khảo

All Rights Reserved

Tìm Hiểu Về Synchronized Trong Java

Ngày này, Thread Programming đang được sử dụng rộng rãi do nhiều lợi ích của nó mang lại. Tuy nhiên một vấn đề lớn của Thread Programming đó là vấn đề đồng bộ hoá hay synchronization. Để hiểu rõ hơn về điều này thì chúng ta cùng tham khảo một ví dụ cụ thể sau.

Trước tiên trong ứng dụng chúng ta có một lớp là CustomerBankAccount dùng để quản lý số tiền gửi Ngân Hàng của khách hàng:

Ở class trên thì:

Thuộc tính balance là số tiền gửi hiện có trong tài khoản.

Phương thức deposit() dùng để giảm số tiền gửi khi khách hàng gửi thêm tiền vào tài khoản.

Phương thức withdraw() dùng để giảm số tiền gửi khi khách hàng rút tiền từ tài khoản.

Phương thước getBallance() dùng để lấy về số tiền trong tài khoản.

Do Ngân Hàng có quá nhiều khách hàng và số lượng giao dịch của khách cũng tăng đáng kể nên để tăng tốc độ xử lý của ứng dụng bạn quyết định sử dụng Multi-Threading thay vì Single-Threading.

Tuy nhiên không lâu sau đó bạn gặp vấn đề đối với loại tài khoản khách hàng doanh nghiệp. Một doanh nghiệp A cấp quyền cho 10 nhân viên của mình có thể thực hiện giao dịch gửi tiền và chuyển tiền từ tài khoản. Chuyện gì xảy ra khi có 10 nhân viên của công ty cùng thực hiện các giao dịch gửi tiền và chuyển tiền vào cùng một thời điểm? Trong trường hợp mỗi giao dịch của một nhân viên được thực hiện trên các Thread khác nhau thì các phương thức deposit() và withdraw() sẽ thực hiện trên các con số balance không khớp nhau.

Cụ thể vào lúc 9h sáng, tài khoản của công ty A có số dư là 10,000$. Sếp công ty này đi ăn nhậu với khách hàng và quyết định rút 2,000$ từ tài khoản. Giao dịch này được xử lý bởi một thead là thread1. Trong khi thread1 đang hoàn tất giao dịch của và vẫn chưa kết thúc thì Kế Toán Trưởng công ty A bắt đầu thực hiện việc kiểm tra số dư tài khoản và thực hiện một giao dịch chuyển khoản ứng tiền 9,000$ cho khách hàng. Giao dịch thứ 2 được thực hiện bởi thread2.

Lúc này do thread1 chưa kết thúc lên thread2 nên vẫn trả về số dư là 10.000$ và Kế Toán Trưởng giao dịch rút tiền 9,000$ của anh ta thực hiện thành công. Đồng thời khi thread1 thực hiện giao dịch thì số tiền dư vẫn lớn hơn 2.000$ nên Sếp công ty A vẫn có thể rút được tiền. Lúc này Ngân Hàng sẽ mất số tiền 1.000$.

Để giải quyết vấn đề trên chúng ta có thể sử dụng synchronized với các method withdraw, deposit và getBallance():

Lúc này thì các phương thức synchronized sẽ chỉ được gọi một lần vào một thời điểm nhất định. Nếu có hai thread cùng gọi phương thức withdraw() thì Java sẽ ưu tiên xử lý ở thread nào tới trước, thread tới sau sẽ bị tạm thời dừng lại cho tới khi thread1 xử lý xong.

Tìm Hiểu Về Thread Pool Trong Java

Thread được sinh ra để thực hiện một nhiệm vụ cụ thể, nhiều Thread cùng xử lý công việc giúp chúng ta giải quyết được bài toán thời gian và hiệu năng khi xử lý một tác vụ nào đó.

Bài toán đặt ra ở đây là có phải cứ sinh ra nhiều Thread thì tác vụ của chúng ta sẽ nhanh hơn mượt mà hơn?

Để giải quyết bài toán đó ThreadPool ra đời để giới hạn số lượng Thread được chạy bên trong ứng dụng chúng ta cùng một thời điểm.

Ví dụ: Khi chúng ta viết chương trình tải các tập tin từ Internet, mỗi tập tin cần 1 Thread để thực hiện quá trình tải, giả sử cần tải 10000 tệp âm thanh thì chúng ta phải cần tới 10000 Thread hoạt động cùng một thời điểm trong cùng một chương trình. Điều này sẽ dễ dẫn đến lỗi quá tải của chương trình, làm ảnh hưởng đến bộ nhớ và hiệu suất của chương trình sẽ rất dễ dẫn đến bị crash vì khó kiểm soát.

Vì vậy, để khắc phục hiện tượng này, Java cho phép chúng ta thay vì phải tạo mới Thread cho mỗi nhiệm vụ, quá trình được thực hiện trong cùng một thời điểm thì các nhiệm vụ, quá trình đó có thể được đưa vào trong một ThreadPool để khi trong ThreadPool có bất kỳ Thread nào đang không phải thực hiện một nhiệm vụ nào thì sẽ có nhiệm vụ gán vào một trong số các Thread đó để thực thi. Điều này sẽ giúp khắc phục được sự tắc nghẽn và chương trình sẽ kiểm soát được các luồng thực thi.

Bên trong ThreadPool, các nhiệm vụ sẽ được chèn vào trong một Blocking Queue. Blocking Queue có thể hiểu là nơi chứa các nhiệm vụ mà các Thread sẽ lấy chúng ra và thực thi lần lượt. Mỗi khi có một nhiệm vụ mới được thêm vào Queue và sau đó sẽ chỉ có một Thread đang không phải thực hiện một nhiệm vụ nào vào Queue lấy nhiệm vụ đó ra, còn các Thread còn lại phải chờ đợi cho đến khi Thread đó lấy nhiệm vụ ra thành công.

Nhưng cũng thật là may, bắt đầu từ** Java 5**, chúng ta đã được cung cấp một thư viên “Executor framework” trong gói java.util.concurrent giúp cho lập trình viên tạo và quản lý các ” ThreadPool” và ” Thread Factories” đơn giản hơn bao giờ hết. Java cung cấp cho chúng ta lớp Executor, sub-interface của nó là ExecutorService và lớp ThreadPoolExecutor kế thừa từ interface ExecutorService trên.

Ở đây chúng ta có thể thấy rằng các đối tượng ThreadPool Executor chấp nhận Runnable và đặt nó vào một Runnable Queue. Hàng đợi này đại diện cho tất cả các nhiệm vụ được gửi để được thực thi bởi Threadpool. Bản thân ThreadPool nó là một chuỗi các luồng đang chờ để kéo Runnables ra khỏi hàng đợi và thực hiện chúng theo các phương thức run() riêng của chúng . Khi ThreadPool running, hay nói cách khác, các luồng trong ThreadPool vẫn còn sống và sẵn sàng thực thi runnables. Khi có một Runnable mới trong hàng đợi, một trong các luồng sẽ kéo nó ra và gọi phương thức run() của Runnable.

2.1. Ví dụ

Run.java

public class Run implements Runnable{ int id; public Run(int id) { chúng tôi = id; } @Override public void run() { System.out.println("Tiến trình đang được thực thi " + id); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Tiến trình đã được thực thi" + id); } }

2.2. Cách hoạt động của ThreadPoolExecutor

Giải thích hoạt động của chương trình trên

Trong dòng code khởi tạo ThreadPoolExecutor:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAlive, unit, workQueue, handler);

chúng ta có 6 tham số:

Đối số 1: (corePoolSize) là số lượng Thread tối thiểu trong ThreadPool. Khi khởi tạo, số lượng Thread có thể là 0. Khi nhiệm vụ được thêm vào thì Thread mới được tạo ra và kể từ đây, nếu số lượng Thread ít hơn corePoolSize thì những Thread mới sẽ được tạo ra đến khi số Thread bằng giá trị của corePoolSize.

Đối số 2: (maximumPoolSize) là số lượng tối đa các Thread trong ThreadPool.

Đối số 3: (keepAliveTime): khi số Thread lớn hơn corePoolSize thì keepAliveTime là thời gian tối đa mà 1 Thread “nhàn rỗi” chờ nhiệm vụ. Khi hết thời gian chờ mà Thread đó chưa có nhiệm vụ thì nó sẽ bị hủy.

Đối số 4: (unit) là đơn vị thời gian của keepAliveTime. Trong ví dụ này thì unit của tôi là TimeUnit.SECONDS.

Đối số 5: (workQueue) là hàng đợi dùng để chứa các nhiệm vụ mà các Thread sẽ lấy chúng ra và thực thi lần lượt, ở đây tôi dùng ArrayBlockingQueue.

Đối số 6: (handler): Hành động khi một request (task) bị từ chối (rejected)

ThreadPoolExecutor.AbortPolicy: Khi một task bị từ chối chương trình sẽ throw ra một runtime RejectedExecutionException.

ThreadPoolExecutor.DiscardPolicy: Khi một task bị từ chối nó đơn gian là sẽ bị “bỏ qua” (discard), lỗi lầm gì đó cũng sẽ không bị throw ra.

ThreadPoolExecutor.DiscardOldestPolicy: Khi một task bị từ chối, chương trình sẽ hủy task “cũ nhất” (oldest) trong queue mà chưa được sử lý, sau đó gửi task vừa bị từ chối vô queue và cố gắng sử lý lại task đó.

Kể từ Java 5 trở đi, ThreadPool đã được xây dựng sẵn trong gói java.util.concurrent, vì vậy chúng ta không cần phải tạo một ThreadPool mà thay vào đó chúng ta sẽ sử dụng các lớp có sẵn của gói này. Java cung cấp cho chúng ta lớp Executor, interface của lớp Executor là ExecutorService. Interface ExecutorService đại diện cho cơ chế thực thi bất đồng bộ có khả năng thực thi các nhiệm vụ trong background. ExecutorService là một đối tượng chịu trách nhiệm quản lý các luồng và thực hiện các tác vụ Runnable được yêu cầu xử lý. Nó tách riêng các chi tiết của việc tạo Thread, lập kế hoạch (scheduling), … để chúng ta có thể tập trung phát triển logic của tác vụ mà không quan tâm đến các chi tiết quản lý Thread.

3.1. Ví dụ

Run.java

public class Run implements Runnable{ int id; public Run(int id) { chúng tôi = id; } @Override public void run() { System.out.println("Tiến trình đang được thực thi " + id); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Tiến trình đã được thực thi" + id); } }

TestThreadPool.java

public class TestThreadPool { public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { pool.submit(new Run(i)); } try { pool.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } pool.shutdown(); } }

3.2. Cách tạo ExecutorService

Ta có thể tạo các thread pool thông qua ExecutorService, các ” tác vụ ” (task) sẽ gửi vào pool và sẽ được sử lý bằng một trong những phương thức mà Executor cung cấp như sau:

Single Thread Executor : Trong ThreadPool chỉ có 1 Thread và các task sẽ được sử lý một cách tuần tự. Tên method “newSingleThreadExecutor()”

Cached ThreadPool : Trong ThreadPool sẽ có rất nhiều Thread, và các task sẽ được sử lý một cách song song. Các Thread cũ sau khi sử lý xong sẽ được sử dụng lại cho tác vụ mới. Mặc định nếu một Thread không được sử dụng trong vào 60 giây thì Thread đó sẽ được hủy (shut down). Tên method “newCachedThreadPool()”

Fixed Thread Pool : Trong ThreadPool sẽ được cố định (fixed) số lượng các Thread. Nếu một task mới được đưa vào mà các thread đều đang “bận rộn” thì task đó sẽ được gửi vào Blocking Queue và ngay sau khi một Thread đã thực thi xong nhiệm vụ của nó thì nhiệm vụ đang ở trong Queue đó sẽ được push ra khỏi Queue và được Thread đó xử lý tiếp. Method “newFixedThreadPool()”

Scheduled Thread Pool : Tương tự như “Cached Thread Pool” nhưng sẽ có khoảng delay giữa các Thread. Method “newScheduledThreadPool()”

Single Thread Scheduled Pool : Tương tự như “Single Thread Executor” nhưng sẽ có khoảng delay giữa các Thread. Method “newSingleThreadScheduledExecutor()”

3.3. Cách sử dụng ExecutorService

Có một vài cách khác nhau để giao nhiệm vụ tới một ExecutorService:

execute(Runnable)

submit(Runnable)

submit(Callable)

invokeAny(…)

execute(Runnable) Phươngthức execute(Runnable) đưa vào một đối tượng java.lang.Runnable và thực thi chúng bất đồng bộ. Với việc sử dụng phương thức này không có cách nào để thu được kết quả của việc thực hiện Runnable (k có callback hoặc giá trị trả về khi thực hiện xong nhiệm vụ).

executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();

submit(Runnable) Phương thức submit(Runnable) cũng đưa vào 1 Runnable nhưng nó trả về một đối tượng Future. Đối tượng Future có thể được sử dụng để kiểm tra nếu Runnable đã hoàn tất việc thực thi.

submit(Callable) Phương thức submit(Callable) tương tự như submit(Runnable) ngoại trừ việc hàm call() của nó cần 1 giá trị trả về để xác định kết quả thu được sau khi hòan thành nhiệm vụ còn phương thức Runnable.run()không thể trả lại kết quả. Kết quả của Callable có thể thu được thông qua đối tượng Future được trả về bởi phương thức submit(Callable)

Sử dụng phương thức future.get() để thu được kết quả. Chú ý phương thực này được thực thi đồng bộ (Asynchronous – tức là sau khi callable hòan thành nhiệm vụ kết quả được trả về nó mới được thực thi).

Nếu 1 trong số task hòan thành (hoặc ném ra 1 ngoại lệ), phần còn lại của Callable sẽ được hủy bỏ (cancelled).

Đoạn mã trên sẽ in ra các kết quả được trả về từ 1 trong những Callable trong tập hợp. Chạy nó vài lần bạn sẽ nhận được những kết quả khác nhau.

Hãy nhớ rằng một công việc có thể hòan thành do một ngoại lệ, vì vậy có nghĩa nó có thể không “thành công” nhiệm vụ. Không có cách nào để biết sự khác biệt trên đối tượng Future.

3.4. Cách kết thúc ExecutorService

shutdown() Khi bạn đã thêm vào các nhiệm vụ cần thiết bạn nên tắt ExcutorService bằng phương thức shutdown(). Khi bạn gọi phương thức này có nghĩa ExcutorService sẽ từ chối nhận thêm các nhiệm vụ (Task), và một khi tất cả các nhiệm vụ đã được thêm vào trước đó đã hòan thành. Sau đó Executor sẽ được tắt (Có nghĩa tất cả các task được thêm vào trước khi gọi shutdown() đều sẽ được thực thi).

executorService.shutdown();

ShutdownNow() Nếu bạn muốn tắt ExecutorService ngay lập tức, bạn có thể gọi phương thức shutdownNow(). Điều này sẽ cố gắng ngắn chặn tất cả các nhiệm vụ ngay lập tức và loại bỏ các nhiệm vụ đã được đưa vào Queue nhưng chưa được thực thi. Không có gì đảm bảo về việc tắt các nhiệm vụ đang chạy hòan tòan, nhưng phương thức này là nỗ lực tốt nhất để tắt chúng.

executorService.shutdownNow();

awaitTermination() Phương thức ExecutorService awaitTermination () sẽ chặn luồng gọi nó cho đến khi ExecutorService tắt hoàn toàn hoặc cho đến khi hết thời gian nhất định. Phương thức awaitTermination () thường được gọi sau khi gọi shutdown () hoặc shutdownNow ().

executorService.shutdown(); executorService.awaitTermination();

Lưu ý: Bạn nên shutdown một ThreadPool bằng cách gọi phương thức shutdown() bởi vì ta không thể chắc chắn được rằng máy ảo Java có thể tự động làm điều đó

All Rights Reserved

Bạn đang đọc nội dung bài viết Tìm Hiểu Về Java 9 Features trên website Cuocthitainang2010.com. Hy vọng một phần nào đó những thông tin mà chúng tôi đã cung cấp là rất hữu ích với bạn. Nếu nội dung bài viết hay, ý nghĩa bạn hãy chia sẻ với bạn bè của mình và luôn theo dõi, ủng hộ chúng tôi để cập nhật những thông tin mới nhất. Chúc bạn một ngày tốt lành!