Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 113

Đỗ Văn Thành – Thanh.dovan9998@gmail.

com – Java Core

Nội dung
Phần 1: Tổng quan...........................................................................................................7

1. Compiler.................................................................................................................7

2. Cấu trúc một chương trình trong Java...............................................................7

2.1 Lớp (Class)..................................................................................................7

2.2 Thuộc tính (Field) (Attribute)...................................................................7

2.3 Phương thức (Method) (Hàm)..................................................................7

2.4 Đối tượng (Object).....................................................................................7

2.5 Một số khái niệm khác...............................................................................8

2.6 n.................................................................................................................10

3. JVM, JRE, JDK...................................................................................................10

3.1 JVM (Java Virtual Machine)...........................................................................10

3.2 JRE (Java Runtime Environment)...................................................................21

3.3 JDK (Java Development Kit)..........................................................................22

4. Memory management............................................................................................22

4.1 Giới thiệu.........................................................................................................22

4.2 Stack Memory.................................................................................................23

4.3 Heap Memory..................................................................................................24

4.4 Reference types...............................................................................................25

4.5 Garbage Collection Process............................................................................26

4.6 n.......................................................................................................................27

5. n.............................................................................................................................27

Phần 2: Java Basic.........................................................................................................28

1. Java Variable and literal........................................................................................28

1.1 Biến.................................................................................................................28
1
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

1.2 Literal..............................................................................................................30

1.3 n.......................................................................................................................30

2. Java Datatypes and Operator.................................................................................30

2.1 Datatypes.........................................................................................................30

2.2 Operator...........................................................................................................31

3. Input & Output......................................................................................................36

3.1 Input...........................................................................................................36

3.2 Output........................................................................................................37

3.3 n..................................................................................................................38

4. Java expression, block and Comment...................................................................38

5. Keyword in Java....................................................................................................38

5.1 Từ khóa static.............................................................................................38

5.2 Từ khóa public, protected, default, private................................................39

5.3 Từ khóa final.............................................................................................41

5.4 n..................................................................................................................43

6. Java if…else..........................................................................................................43

7. Switch statement...................................................................................................44

8. Loop......................................................................................................................44

8.1. Vòng lặp while; do-while...............................................................................44

8.2. Vòng lặp for...................................................................................................44

8.3. For-Each Loop................................................................................................45

8.4. n......................................................................................................................45

9. Array......................................................................................................................45

10. String...................................................................................................................46

11. n...........................................................................................................................49
2
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 4: Hướng đối tượng OOP.....................................................................................50

1. Giới thiệu..........................................................................................................50

2. Tính đóng gói (Encapsulation).........................................................................50

3. Tính kế thừa (Inheritance)................................................................................52

4. Tính trừu tượng (Abstraction)..........................................................................54

4.1 Định nghĩa trừu tượng và giai đoạn thiết kế....................................................54

4.2 Giai đoạn triển khai.........................................................................................55

4.3 So sánh giữa Abstract Class và Interface........................................................57

4.4 N......................................................................................................................58

5. Tính đa hình (Polymorphism)...........................................................................58

5.1 Đa hình lúc thực thi (Đa hình runtime):................................................58

5.2 Đa hình lúc biên dịch (Đa hình compiler hay static polymorphism):. 60

5.3 Overloading và Overriding........................................................................61

5.4 n..................................................................................................................62

6. n........................................................................................................................62

Phần 5: Ngoại lệ Exception...........................................................................................63

1. Giới thiệu..........................................................................................................63

2. Try-Catch-final Block.......................................................................................64

3. Throw và Throws..............................................................................................68

3.1. Throw.............................................................................................................68

3.2. Throws............................................................................................................69

3.3. So sánh Throw và Throws..............................................................................70

3.4. n......................................................................................................................70

4. Lan truyền ngoại lệ (exception propagation)....................................................70

5. Một số chú ý.....................................................................................................70


3
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

6. Java Custom Exception.....................................................................................72

7. n........................................................................................................................73

Phần 6: Collection.........................................................................................................74

1. Giới thiệu..........................................................................................................74

2. List....................................................................................................................75

2.1 ArrayList....................................................................................................75

2.2 Vector (ít dùng)..........................................................................................77

2.3 LinkedList..................................................................................................78

2.4 So sánh và cách sử dụng ArrayList, LinkedList, Vector...........................79

2.5 n..................................................................................................................80

3. Map...................................................................................................................80

3.1. HashMap....................................................................................................80

3.2. HashTable..................................................................................................81

3.3. LinkedHashMap.........................................................................................82

3.4. TreeMap.....................................................................................................82

3.5. N.................................................................................................................83

4. Set.....................................................................................................................83

4.1 HashSet......................................................................................................83

4.2 LinkedHashSet...........................................................................................85

4.3 TreeSet......................................................................................................85

4.4 n.................................................................................................................86

5. ArrayDeque.......................................................................................................86

6. PriorityQueue....................................................................................................86

7. n........................................................................................................................87

Phần 7: Java 8................................................................................................................88


4
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

1. Defaut Method.......................................................................................................88

2. Funcional Interfaces..............................................................................................88

3. Lamda Expressions...............................................................................................88

4. Method References................................................................................................90

5. Stream API............................................................................................................92

5.1 Giới thiệu...................................................................................................92

5.2 Ví dụ...........................................................................................................94

5.3 Stream API với I/O....................................................................................96

5.4 Parallel Streams (Luồng song song)..........................................................96

5.5 Hạn chế......................................................................................................97

5.6 n..................................................................................................................97

6. Collection API Enhencement................................................................................97

7. Annotation.............................................................................................................97

8. Date Time API......................................................................................................97

9. Optional.................................................................................................................97

10. n...........................................................................................................................97

Phần 8: Thread và MultiThread....................................................................................99

1. Giới thiệu...............................................................................................................99

2. Tạo Thread trong Java.........................................................................................101

2.1 Extends từ Class Thread................................................................................101

2.2 Implement từ Interface Runable....................................................................101

2.3 Kết hợp tạo Thread với Lamda Expressions.................................................102

2.4 n.....................................................................................................................103

3. Process Schedulers..............................................................................................103

4. Process Table and Process Control Block (PCB)................................................103


5
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

5. Interrupt...............................................................................................................103

6. Các Method của Thread (thường được sử dụng)................................................103

7. ThreadId, ThreadName, Priority.........................................................................104

8. Xử lý Exception cho Thread...............................................................................105

9. Các loại Thread trong Java, Thread Pool............................................................105

9.1 Force Threads và Background Threads.........................................................105

9.2 Thread Pool...................................................................................................106

9.3 Cách khai báo và sử dụng Thread Pool.........................................................107

9.4 n.....................................................................................................................107

10. Safety Thread....................................................................................................107

10.1 Giới thiệu.....................................................................................................107

10.2 Synchronized...............................................................................................108

10.3 Class Atomic...............................................................................................109

10.4 Lock từ gói java.util.concurrent.locks.........................................................110

10.5 Thread safe Collection................................................................................111

10.6 Từ khóa “Vollatide”....................................................................................112

10.7 Sử dụng từ khóa final..................................................................................113

10.8 N..................................................................................................................113

11. Deadlock............................................................................................................113

12. n.........................................................................................................................114

6
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 1: Tổng quan


1. Compiler

2. Cấu trúc một chương trình trong Java


2.1 Lớp (Class)
Class là mô tả về các đối tượng được tạo ra.

2.2 Thuộc tính (Field) (Attribute)


Thuộc tính (Field) chính là các giá trị của Class. Sau khi các đối tượng được tạo ra từ
lớp thì các thuộc tính này sẽ trở thành đặc điểm của đối tượng đó.
[khả_năng_truy_cập] kiểu_thuộc_tính tên_thuộc_tính [= giá_trị_ban_đầu];

Thuộc tính tương tự như các biến bên trong các hàm nhưng khác nhau về phạm vi sử
dụng. Thuộc tính có thể sử dụng ở mọi vị trí trong class.
Khi khai báo một biến cùng tên với một thuộc tính thì hệ thống vẫn sẽ xác định được
đâu là biến và đâu là thuộc tính. Tuy nhiên, ta nên sử dụng từ khóa this.tên_thuộc_tính
khi muốn truy cập vào thuộc tính. (This ám chỉ cho class hiện tại)

2.3 Phương thức (Method) (Hàm)


Method (Phương thức) định nghĩa cách ứng xử của Class. Một Method là tập hợp các
khối lệnh để thực thi một chức năng nào đó.
[khả_năng_truy_cập] kiểu_trả_về tên_phương_thức ( [tham_số] ) {

// Các dòng code

2.4 Đối tượng (Object)


Đối tượng (Object) chứa các method (phương thức) và properties(thuộc tính) để tạo ra
một kiểu dữ liệu hữu ích. Object xác định hành vi (hoạt động, thao tác) của Class. Một
7
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

đối tượng có thể là một cấu trúc dữ liệu (data structure), một biến (variable) hoặc một
chức năng (function).
Đối tượng chính là thứ ta muốn quản lý. Một đối tượng thì có trạng thái và hành vi.
Trạng thái chính là các đặc thù, đặc trưng của đối tượng đó.
Hành vi chính là các hành động của đối tượng đó.
Một Class là một Blueprint (kế hoạch) hay Prototype (nguyên mẫu) xác định biến và
các phương thức (hay function) chung với tất cả các đối tượng cùng loại. Một Object (đối
tượng) là một cụ thể, thể hiện của một Class.
2.5 Một số khái niệm khác
2.5.1 Constructor (Hàm tạo)
Là một phương thức đặc biệt để khởi tạo một đối tượng với những giá trị ban đầu.
Constructor được gọi khi một đối tượng của Class được tạo. Và Constructor phải có cùng
tên với Class định nghĩa nó.

8
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

“ static block” và “Test block” là 2 “instance initialiser” với một Constructor mặc
định.
2.5.2 Mối liên hệ giữa instance, Object và Reference (Tham chiếu)
instance và Object có ý nghĩa tương đương nhau và cùng được khởi tạo với từ khóa
new. Tuy nhiên, khi ta nói về mặt đối tượng của một kiểu dữ liệu cụ thể (được tạo ra) thì
ta dùng Instence, còn khi nói về mặt đối tượng thì ta dùng Object.
Khi ta nói Reference (Tham chiếu) tức là ta đang nói đến một biến lưu địa chỉ một
Object/ instance. (Reference)
Ví dụ:
Đầu tiên ta tạo một class Student. Sau đó:
Ta tạo một đối tượng:
Student St1 = new Student();
Ở ví dụ trên, ta hiểu như sau:
 Class (ví dụ ở đây là class Student) thì chưa sinh ra bộ nhớ. Chỉ khi tạo ra một
đối tượng thì mới được cấp phát bộ nhớ trong Heap. Còn khi viết class mà chưa

9
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

tạo đối tượng thì các method, thuộc tính của Class sẽ được lưu trong vùng
Method Area dưới dạng text code.
 Student ám chỉ kiểu dữ liệu là của Class Student. St1 là Reference lưu địa chỉ
của đối tượng. St1 mặc định được cấp phát 4byte trong vùng Stack Memory.
Student() mới chính là đối tượng và nó chứa mọi thuộc tính, Method của Class
Student. Đối tượng Student() được lưu trong Heap.
2.5.3 Block
Chính là các khối lệnh
2.5.4 N
n
2.6 n

3. JVM, JRE, JDK


3.1 JVM (Java Virtual Machine)
3.1.1 Giới thiệu
JVM (Máy ảo Java) là một máy trừu tượng cho phép máy tính của bạn chạy chương
trình Java.
Khi chạy chương trình Java, trước tiên, trình biên dịch Java sẽ biên dịch code Java
(.java) thành bytecode (.class). Sau đó, JVM dịch bytecode(.class) thành mã máy gốc (tập
hợp các lệnh mà CPU của máy tính thực thi trực tiếp). Java là một ngôn ngữ độc lập với
nền tảng. Đó là bởi vì khi bạn viết code Java, nó được viết cho JVM chứ không phải máy
tính vật lý (máy tính) của bạn.
Máy ảo Java tên tiếng Anh là Java Virtual Machine (viết tắt là JVM) là:
 Một Engine cung cấp Runtime Environment (môi trường chạy mã) để điều
khiển mã Java hoặc các ứng dụng.
 Nó chuyển đổi Java Bytecode (.class) thành ngôn ngữ máy tính hiểu được.
 JVM là một phần của JRE (Môi trường chạy Java - Java Run Environment).
Nó là viết tắt của Java Virtual Machine.
Trong các ngôn ngữ lập trình khác, trình biên dịch (compiler) tạo mã máy cho một hệ
thống cụ thể. Tuy nhiên, trình biên dịch Java (Java Compiler) tạo mã cho một máy ảo
10
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

được gọi là Máy ảo Java (JVM). Đầu tiên, mã Java được tuân thủ theo bytecode (.class).
Bytecode này được diễn giải trên các máy khác nhau giữa hệ thống máy chủ và Java
Source, Bytecode là ngôn ngữ trung gian. JVM chịu trách nhiệm phân bổ không gian bộ
nhớ.

Conpiler sẽ biên dịch một chương trình java thành file java dạng .class, sau đó,
file.class đó được coi là đầu vào của JVM, JVM sẽ nhận và thực thi file đó.

Để thực hiện chức năng của mình, JVM sẽ thực hiện theo các bước sau:
 Loads the code.
11
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Verifies code.
 Executes the code.
 Provides a run-time environment for various applications.
 JVM provides a Memory area.
 Provides a Register set.
 JVM provides the garbage collection heap.
 Reports fatal errors.
 Provides a class file format

Kiến trúc máy ảo Java (JVM Architecture) gồm có 3 phần chính:

12
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Class Loader SubSystem


 Runtime Data Areas (JVM Memory areas)
 Execution Engine
3.1.2 Class Loader SubSystem
ClassLoader SubSystem là một hệ thống con được sử dụng để tải các class file (Java
ClassLoader là một phần của JRE, tải tự động các class file vào JVM). Nó thực hiện ba
chức năng chính: Loading, Linking và Initialization (Khởi tạo).
Loading: Thao tác này tải các tệp từ bộ nhớ phụ vào bộ nhớ chính (RAM) để thực thi.
Classloader đọc tệp .class, tạo dữ liệu nhị phân tương ứng và lưu nó trong vùng method
area. Loading bao gồm các thành phần:
 Bootstrap Class Loader: Chịu trách nhiệm tải các class từ classpath bootstrap,
chính là runtime.jar (Tất cả các thư viện tiêu chuẩn như jav.lang.*, …). Bộ tải
này giữ mức ưu tiên cao nhất cho quá trình loader. Bootstrap ClassLoader
không có bất kỳ ClassLoader cha nào. Nó còn được gọi là Primodial
ClassLoader.( Đây chính là các thư viện được viết bằng Native code)
 Extension ClassLoader: Là con của Bootstrap Class Loader. Chịu trách nhiệm
tải các class mở rộng (extension classes). Nó tải các tệp từ thư mục jre / lib /
ext hoặc bất kỳ thư mục nào khác được trỏ bởi thuộc tính hệ
thống java.ext.dirs. (Đây chính là code của bên thứ 3)
 System/Application ClassLoader: Nó tải các class kiểu ứng dụng được tìm thấy
trong tùy chọn dòng lệnh CLASSPATH, -classpath hoặc -cp biến môi
trường. Application ClassLoader là một lớp con của Extension ClassLoader.
(Đây chính là code người dùng viết)
Mô hình phân cấp ủy quyền ClassLoader (The ClassLoader Delegation Hierarchy
Model) luôn hoạt động theo thứ tự Application ClassLoader-> Extension ClassLoader->
Bootstrap ClassLoader. Bootstrap ClassLoader luôn được ưu tiên cao hơn, tiếp theo là
Extension ClassLoader và Application ClassLoader.

13
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Nguyên tắc hoạt động của ClassLoader: Mô hình phân cấp ủy quyền, nguyên tắc hiển
thị, thuộc tính Uniqueness:
 JVM và Java ClassLoader sử dụng một thuật toán gọi là thuật toán phân cấp ủy
quyền để tải lên các Class. ClassLoader thực hiện các hành động được xây dựng
trên mô hình phân cấp ủy quyền:
ClassLoader luôn tuân theo nguyên tắc phân cấp ủy quyền.
Bất cứ khi nào JVM đi qua một class, nó sẽ kiểm tra xem class đó đã được
tải hay chưa.
Nếu class đã được tải trong Method area thì JVM sẽ tiến hành thực thi.
Nếu class không có trong Method area thì JVM yêu cầu ClassLoader
SubSystem tải class cụ thể đó, sau đó ClassLoader SubSystem bàn giao
quyền điều khiển cho Application ClassLoader.
Sau đó, Application ClassLoader sẽ ủy quyền yêu cầu tới Extension
ClassLoader và Extension ClassLoader đến lượt mình sẽ ủy quyền yêu cầu
tới Bootstrap ClassLoader.

14
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Bootstrap ClassLoader sẽ tìm kiếm trong đường dẫn Bootstrap classpath


(JDK/JRE/LIB). Nếu class có sẵn thì nó sẽ được tải. Nếu không thì yêu cầu
sẽ được ủy quyền cho Extension ClassLoader.
Extension ClassLoader tìm kiếm class trong đường dẫn mở rộng Extension
Classpath (JDK/JRE/LIB/EXT). Nếu class khả dụng thì nó sẽ được tải. Nếu
không thì yêu cầu sẽ được ủy quyền cho Application ClassLoader.
Application ClassLoader tìm kiếm class trong Application Classpath. Nếu
class có sẵn thì nó sẽ được tải. Nếu không thì sinh ra một Exception:
ClassNotFoundException.
 Nguyên tắc hiển thị (Visibility Principle): một class được nạp bởi ClassLoader
cha sẽ hiển thị với ClassLoader con nhưng một class được nạp bởi ClassLoader
con sẽ không hiển thị với ClassLoader cha. Giả sử một class example.class đã
được nạp bởi Extension ClassLoader, thì class đó chỉ hiển thị với Extension
ClassLoader và Application ClassLoader mà không hiển thị với Bootstrap
ClassLoader. Nếu class đó được cố gắng tải lại bằng Bootstrap ClassLoader, nó
sẽ đưa ra một Exception: java.lang.ClassNotFoundException.
 Thuộc tính Uniqueness: Thuộc tính Uniquesness đảm bảo rằng các class là duy
nhất và không có sự lặp lại của các class. Điều này đảm bảo rằng các class được
tải bởi bộ nạp lớp cha không được tải bởi bộ nạp lớp con. Nếu trình nạp lớp cha
không thể tìm thấy class đó, thì lúc đó trình nạp lớp con mới được phép thực
hiện.
Các thuộc tính (Methods) của Java.lang.ClassLoader: Sau khi JVM yêu cầu class, một
vài bước phải được thực hiện để tải một class. Các Class được tải theo mô hình ủy quyền
nhưng có một vài Methods hoặc Funcions đóng vai trò quan trọng trong việc tải một
Class:
 loadClass (String name, boolean resolve): sử dụng để tải các class được tham
chiếu bởi JVM. Nó lấy tên của class làm tham số. Đây là kiểu
loadClass(String, boolean).

15
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 defineClass(): là một phương thức cuối cùng và không thể bị ghi đè. Phương
thức này được sử dụng để định nghĩa một mảng kiểu byte như một dạng của
class. Nếu class không hợp lệ thì nó sẽ đưa ra cảnh báo: ClassFormatError.
 findClass (String name): sử dụng để tìm một class được chỉ định. Phương thức
này chỉ tìm nhưng không tải class.
 findLoadedClass (String name): sử dụng để xác minh xem Class được tham
chiếu bởi JVM đã được tải trước đó hay chưa.
 Class.forName(String name,boolean initialize,ClassLoader loader) :
Phương thức này dùng để nạp class cũng như khởi tạo class. Phương thức này
cũng cung cấp tùy chọn để chọn một trong các ClassLoader bất kỳ. Nếu tham
số ClassLoader là NULL thì Bootstrap ClassLoader sẽ được sử dụng.
Ví dụ đoạn code sau sẽ được thực hiện trước khi tải một class:
protected synchronized Class<?>
loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = findLoadedClass(name);
try {
if (c == NULL) {
if (parent != NULL) {
c = parent.loadClass(name, false);
}
else {
c = findBootstrapClass0(name);
}
}
catch (ClassNotFoundException e)
{
System.out.println(e);
}
}
}
Lưu ý: Nếu một class đã được tải, nó sẽ trả về class đó. Nếu không, nó sẽ ủy
quyền tìm kiếm class mới cho trình nạp class cha. Nếu trình nạp class cha không tìm thấy
class, loadClass() sẽ gọi phương thức findClass() để tìm và tải class. Phương
thức findClass () tìm kiếm class trong ClassLoader hiện tại nếu ClassLoader cha không
tìm thấy class đó.

16
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Linking: Kết hợp các file trong chương trình chính. Quá trình này bao gồm:
verification, preparation, và resolution (optionally).
 Verification: Sau khi các tệp .class được tải vào bộ nhớ, quá trình xác minh bắt
đầu. Hệ thống sẽ tiến hành kiểm tra các liên kết để có thể loại bỏ các hoạt động
không cần thiết do quá trình thông dịch thực hiện tại thời điểm chạy giúp nâng
cao hiệu suất của trình thông dịch (interpreter) (Do trong Java, trình tạo mã Just-In-
Time (Xem phần JIT trong Execution Engine) chuyển đổi bytecode thành mã máy gốc có cùng

cấp độ. Do đó, Java vừa được biên dịch cũng như thông dịch). Đồng thời, nó sẽ kiểm tra

xem việc hình thành và tạo tệp có phải từ một compiler hợp lệ hay không, nếu
không thì trả về 1 Exception: java.lang.Verify. Một số quá trình xác minh:
 Các biến chưa được khởi tạo
 Các quy tắc truy cập đối với private data and methods không bị vi phạm.
 Methods (Các phương thức) gọi khớp với đối tượng tham chiếu (Object
Reference).
 Không có lỗi operand stack overflows or underflows
 Các đối số cho tất cả các tham số JVM là các kiểu hợp lệ.
 Đảm bảo rằng các class cuối cùng không được phân class con và Method
cuối cùng không bị ghi đè.
 Kiểm tra xem tất cả các tham chiếu toàn cục và tham chiếu cục bộ (field
references and method references) có tên hợp lệ, class hợp lệ và kiểu hợp lệ
hay không.
 Preparation: JVM phân bổ bộ nhớ cho các biến và khởi tạo bộ nhớ về giá trị
mặc định (Giá trị 0, NULL)
 Resolution(optionally): là quá trình thay thế các tham chiếu tượng trưng
(symbolic references: Là các chuỗi được sử dụng để truy xuất đối tượng thật, chứa đựng
thông tin của class dưới dạng biểu tượng tức là tập hợp các text để mô tả đối tượng được

tham chiếu. Các hàm được gán nhãn dạng ảo ví dụ #1, #2,… ) bằng các tham chiếu trực

tiếp (direct references: Nơi viết ra các Method, các hàm đó) . Nó sử dụng tìm kiếm trong
Method area để xác định vị trí thực thể được tham chiếu.

17
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Initialization (Khởi tạo): Gán tất cả các biến static với các giá trị cụ thể của chúng
trong khối chương trình. Việc thực thi diễn ra từ trên xuống dưới trong một class và từ
cha đến con trong hệ thống phân cấp class.
3.1.3 Runtime Data Areas (JVM Memory area)
JVM cần vùng Runtime Data Areas để lưu trữ các file class và thực thi chúng.
Runtime Data Areas bao gồm 5 vùng chính:
 Method (Class) Area: Tất cả các class-level information (như tên class, tên
class cha trực tiếp, các method, biến,…) sẽ được lưu ở đây bao gồm cả static
variables. Do mỗi JVM chỉ có 1 vùng method area nên tất cả sẽ cùng chia sẻ tài
nguyên. JVM lưu trữ một số thông tin cho mỗi tệp .class trong method area.
Thông tin này bao gồm:
 Tên hợp lệ của class được tải và class cha trực tiếp của nó.
 .class có liên quan đến giao diện hoặc một enum hoặc một class không
 Thông tin về chỉnh sửa, biến và Method, v.v.

 Heap Area: Tất cả các Object và các biến tương ứng của chúng sẽ được lưu trữ
ở đây (). Ngoài ra chỉ có một Vùng Heap area trên mỗi JVM. Vì các vùng
Method area và Heap Area chia sẻ bộ nhớ cho nhiều thread (luồng), nên dữ liệu
được lưu trữ không an toàn cho thread. Sau khi tải tệp .class, JVM tạo một
Object kiểu Class để đại diện cho tệp này trong bộ nhớ Heap. Ta có thể sử dụng
Object Class này để nhận thông tin cấp độ class như tên của class, tên cha, các
Method và thông tin biến, v.v. Để lấy tham chiếu đối tượng này, chúng ta có thể
sử dụng Method getClass() của class Object.

 Stack Area: Mỗi thread sẽ được tạo một Runtime Stack riêng biệt. Đối với mỗi
lệnh gọi Method, một cổng sẽ được thực hiện trong Stack Memory được gọi là
Stack Frame và sẽ bị xóa khi lệnh gọi Method hoàn tất. Tất cả các biến cục bộ
sẽ được tạo trong Stack memory. Stack Area là vùng an toàn theo thread vì nó
không phải tài nguyên được chia sẻ. Stack Frame được chia thành ba phần nhỏ:

18
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Local Variable Array: Liên quan tới method: số biến local variables được
gọi và giá trị tương ứng của chúng sẽ được lưu ở đây.
 Operand stack(Ngăn xếp toán hạng): Nếu bất kỳ thao tác trung gian nào
được yêu cầu thực hiện, Operand stack hoạt động như không gian làm
việc runtime để thực hiện thao tác.
 Frame data: Trong trường hợp có Exeption, thông tin khối đang thực hiện
sẽ được duy trì trong Frame data.

 Heap: Các string constant pool, Biến toàn cục (Biến được khai báo trong class mà
nằm ngoài tất cả các hàm)(Biến class, thuộc tính); biến của object.
 Stack: Biến local (Biến nằm trong hàm, nằm trong method, block); biến object
(Tên biến chứa Object, ví dụ trên là example1)
19
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Method (Class Area): Các biến static (Biến được khai báo trong một class và nằm
ngoài các hàm, method).

 PC Registers: Mỗi thread có các PC Registers riêng biệt, để lưu địa chỉ của
lệnh thực thi hiện tại khi lệnh được thực hiện, PC Registers sẽ được cập nhật
với lệnh tiếp theo. Có vai trò như con trỏ trong C
 Native Method stacks: Native Method Stack chứa thông tin về Method gốc
liên quan đến các nền tảng gốc. Đối với mỗi thread, một Native Method Stack
riêng biệt sẽ được tạo. ⇨ Ví dụ: nếu đang chạy JVM trên Windows, nó sẽ chứa
thông tin liên quan đến Windows. Tương tự như vậy, nếu đang chạy trên Linux,
nó sẽ có tất cả thông tin liên quan đến Linux mà chúng ta cần.

3.1.4 Execution Engine


Execution Engine(Công cụ thực thi) “ .class” (bytecode). Nó đọc từng dòng bytecode,
sử dụng dữ liệu và thông tin có trong các vùng bộ nhớ khác nhau và thực hiện các
lệnh. Nó có thể được phân thành ba phần:
 Interpreter (Trình thông dịch): Nó thông dịch từng dòng bytecode và sau đó
thực thi. Điểm bất lợi ở đây là khi một phương thức được gọi nhiều lần, mỗi lần
cần phải diễn giải.

20
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Just-In-Time Compiler (Trình biên dịch Just-In-Time) (JIT) : Nó được sử dụng


để tăng hiệu quả của trình thông dịch. Nó biên dịch toàn bộ bytecode và thay
đổi nó thành mã gốc để bất cứ khi nào trình thông dịch thấy các lệnh gọi
Method lặp lại, JIT sẽ cung cấp mã gốc trực tiếp cho phần đó để không cần phải
diễn giải lại, do đó hiệu quả được cải thiện.
 Intermediate Code Generator (Bộ tạo mã trung gian): Tạo mã trung gian.
 Code Optimizer (Trình tối ưu hóa mã): Chịu trách nhiệm tối ưu hóa mã
trung gian được tạo ở trên
 Target Code Generator (Trình tạo mã đích): Chịu trách nhiệm tạo mã máy
gốc.
 Profiler (Hồ sơ): Một thành phần đặc biệt, chịu trách nhiệm tìm kiếm các
điểm nóng, tức là phương thức có được gọi nhiều lần hay không.
 Garbage Collector: Nó hủy bỏ các đối tượng không được tham chiếu.
Quá trình làm việc của JIT
Các Method không được biên dịch ở lần gọi đầu tiên. Đối với các Method, JVM sẽ
đếm số lần gọi, và con số này sẽ tăng lên mỗi khi Method được gọi. Các Method được
JVM thông dịch cho đến khi số cuộc gọi vượt quá giới hạn của JIT (Ngưỡng mà JIT giúp
cải thiện hiệu suất biên dịch và giúp khởi động nhanh JVM)(Ngưỡng do JVM quy định).
Do đó, các Method được sử dụng nhiều sẽ được biên dịch ngay khi khởi động JVM, và
các Method ít được sử dụng sẽ được biên dịch sau đó. Sau khi một Method được biên
dịch bởi JIT, số lần gọi của nó được đặt lại về 0 và các lần gọi Method tiếp theo sẽ tăng
số lần gọi của nó. Khi số lần gọi của một Method đạt đến ngưỡng biên dịch lại của JIT,
trình biên dịch JIT sẽ biên dịch Method lần thứ hai, áp dụng nhiều tối ưu hóa hơn so với
quá trình biên dịch trước đó. Quá trình này được lặp lại cho đến khi đạt được mức tối ưu
hóa tối đa. Các Method được sử dụng thường xuyên nhất luôn được tối ưu hóa để tối đa
hóa lợi ích hiệu suất của việc sử dụng trình biên dịch JIT.
3.1.5 Java Native Interface (JNI)
JNI là một giao diện tương tác với Native Method Libraries, và cung cấp các Native
Librarys (C, C++) được yêu cầu để thực thi chương trình. Nó cho phép JVM gọi các thư

21
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

viện C/C++ Librarys hoặc được gọi bởi các thư viện này. Nó là một tập hợp các Native
Libraries(C, C++) mà được yêu cầu bởi Execution Engine.

3.2 JRE (Java Runtime Environment)


JRE (Môi trường thực thi Java) là gói phần mềm cung cấp các thư viện Java class,
cùng với Máy ảo Java (JVM) và các thành phần khác để chạy các ứng dụng được viết
bằng Java.
JRE = Java class + JVM

3.3 JDK (Java Development Kit)


JDK (Java Development Kit) là một bộ công cụ phát triển phần mềm để phát triển các
ứng dụng trong Java.
JDK = JRE + Compilers + Debuggers…
4. Memory management
4.1 Giới thiệu
Java tự động quản lý bộ nhớ nhờ công cụ Garbage Collector. Công cụ Garbage
Collector chạy trong nền giúp dọn dẹp những đối tượng không sử dụng và giải phóng bộ
nhớ. Tuy nhiên, có một số đối tượng không bị xóa bỏ bởi Garbage Collector ngay cả khi
không còn được sử dụng do không đủ điều kiện để Garbage Collector xóa bỏ. Khi các
đối tượng này đầy bộ nhớ thì chương trình bị Crash và xuất hiện lỗi OutOfMemoryError

22
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

4.2 Stack Memory


Lưu trữ các tham chiếu đến các đối tượng trong Heap và lưu trữ các kiểu dữ liệu (Hay
còn gọi là kiểu dữ liệu nguyên thủy primitive types trong Java như int,…). Ngoài ra, các
biến trên Stack được truy cập ở một mức nhất định gọi là phạm vi biến. Chỉ các đối tượng
trong phạm vi mới sử dụng được. Ví dụ chương trình không có biến toàn cục nào, và chỉ
có các biến cục bộ. Thì khi trình biên dịch thực thi phần thân của chương trình thì nó chỉ
có thể truy cập được các biến cục bộ trong phần thân đó mà không thể truy cập các biến
cục bộ khác. Khi Method hoàn thành và trả về giá trị thì đỉnh của stack sẽ thoát ra và lúc
nào phạm vi truy cập của trình biên dịch sẽ được thay đổi.

23
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

4.3 Heap Memory


Heap lưu trữ các đối tượng thực tế trong bộ nhớ và được tham chiếu bởi các biến từ
Stack.
Ví dụ:
StringBuilder builder = new StringBuilder();
Từ khóa “new” giúp đảm bảo trong Heap còn đủ bộ nhớ và tạo một đối tượng kiểu
StringBuilder tham chiếu đến nó thông qua tham chiếu builder trong Stack.
Mỗi 1 JVM chỉ có một Heap Memory được dùng chung cho tất cả các thread. Heap
Memory được cấu tạo gồm 2 vùng chính là Young Generation và Old Generation.

Kích thước tối đa của Stack và Heap không được xác định trước mà phụ thuộc vào
máy đang chạy.
4.3.1 Young Generation
Đây là nới lưu tất cả những biến mới được khởi tạo. Khi vùng nhớ này đầy thì công cụ
Garbage Collection bắt đầu hoạt động. Công cụ Garbage Collection trong Young
Generation được gọi là Minor Garbage Collection. Young Generation được chia làm 3
phần gồm Eden Memory space và 2 Survivor Memory spaces (S0 và S1).
Việc lưu trữ trong Young Generation được thực hiện theo nguyên tắc:
 Hầu hết các biến mới được tạo đặt tại vùng Eden Memory

24
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Khi vùng Eden Memory đầy thì Minor Garbage Collection hoạt động để dọn
dẹp các đối tượng không còn được sử dụng. Các đối tượng còn lại được chuyển
sang vùng Survivor Memory space.
 Minor Garbage Collection sẽ kiểm tra các đối tượng còn sót lại sau dọn dẹp và
chuyển chúng sang vùng Survivor Memory space khác. Do đó, một trong các
vùng Survivor Memory space luôn luôn trống.
 Các đối tượng còn sót lại sau nhiều chu kỳ dọn dẹp sẽ được chuyển sang vùng
Old Generation

4.3.2 Old Generation


Old Generaton lưu trữ những đối tượng còn sót lại sau nhiều chu kỳ dọn dẹp của
Minor Garbage Collection, và được chuyển sang từ Young Generation. Thông thường thì
công cụ Garbage Collection sẽ tiến hành dọn dẹp khi vùng nhớ Old Generaton đầy.
Công cụ Garbage Collection trong Old Generation được gọi là Major Garbage
Collection và thường mất nhiều thời gian hơn Minor Garbage Collection.
Việc lưu trữ trong Old Generation được thực hiện theo nguyên tắc:
 Dùng để lưu những đối tượng tồn tại lâu và còn sót lại sau nhiều chu kỳ dọn
dẹp của Minor Garbage Collection trong Young Generation.
 Khi bộ nhớ trong Old Generation đầy thì Major Garbage Collection bắt đầu
hoạt động.
 Số lượng Major Garbage Collection ít hơn số lượng Minor Garbage Collection
 Thời gian công cụ Major Garbage Collection làm việc nhiều hơn so với công
cụ Minor Garbage Collection
 Các công cụ Major Garbage Collection mất nhiều thời gian làm việc và làm
cho các ứng dụng không phản hồi

4.4 Reference types


Trong Java có 4 kiểu tham chiếu từ Stack đến Heap: strong, weak, soft, và phantom
references.

25
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Strong reference: Đây là kiểu chúng ta hay dùng. Đối tượng được khai báo với
kiểu tham chiếu này sẽ không được dọn dẹp bởi công cụ Garbage Collection.
Ví dụ về Strong References:
StringBuilder builder = new StringBuilder();
 Weak reference: Các tham chiếu kiểu này có thể không còn tồn tại sau chu trình
dọn dẹp tếp theo của Garbage Collection. Ví dụ về Weak References:
WeakReference<StringBuilder> builder = new WeakReference<>(new StringBuilder());
 Soft reference: Đây là kiểu tham chiếu này được sử dụng cho các tình huống
memory-sensitive. Các đối tượng sẽ chỉ được dọn dẹp khi ứng dụng sắp hết bộ
nhớ. Java đảm bảo rằng tất cả các đối tượng được tham chiếu kiểu Soft
reference đều được dọn dẹp trước khi xảy ra lỗi OutOfMemoryError. Ví dụ
về Soft References:
SoftReference<StringBuilder> builder = new SoftReference<>(new StringBuilder());
 Phantom reference: Sử dụng để lên lịch dọn dẹp các đối tượng mà biết chắc
chắn rằng chúng không còn được sử dụng nữa. Chỉ được sử dụng với một hàng
đợi tham chiếu vì phương thức get() đến các tham chiếu đó luôn trả về giá trị
NULL.

4.5 Garbage Collection Process


Tùy thuộc vào loại tham chiếu và biến được tham chiếu có còn được sử dụng trong
Stack nữa không mà Garbage Collection Process hoạt động. Quá trình dọn dẹp bởi
Garbage Collection:
 Được thực hiện tự động bởi Java
 Khi quá trình này hoạt động, tất cả các Thread sẽ bị tạm dừng.
 Đây là một quá trình phức tạp khi dọn dẹp và giải phóng bộ nhớ.
Meta Space, Metadata?
Từ Java 8, vùng nhớ mà JVM dùng để giữ các class của nó được gọi là Metaspace (Từ
Java 7 trở về trước gọi là PermGen). Metaspace theo mặc định tự động tăng kích thước
của nó (lên đến những gì hệ điều hành cơ bản cung cấp), trong khi PermGen luôn có kích
thước tối đa cố định. => Hiểu đơn giản, MetaSapce là tên gọi khác của Method Area
26
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Metaspace garbage collection: Dọn dẹp các Class chết và kích hoạt bộ nạp Class khi
mức sử dụng metadata (siêu dữ liệu)(ví dụ: các class, method,...) của class đạt
đến MaxMetaspaceSize. Kích thước Metaspace tự động tăng trong bộ nhớ gốc theo yêu
cầu để tải metadata (siêu dữ liệu) class nếu không bị hạn chế với -
XX:MaxMetaspaceSize.
Metadata hiểu đơn giản là một phần của Heap Memory.
4.6 n
5. n

27
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 2: Java Basic


1. Java Variable and literal
1.1 Biến
Biến local:
 Là biến được khai báo bên trong một hàm, một phương thức, một khối lệnh.
 Chỉ được sử dụng trong phạm vi hàm, phương thức, khối lệnh khởi tạo. Khi ra
khỏi đây thì sẽ bị mất giá trị
 Không có giá trị mặc định khi vừa khởi tạo và được lưu trong Stack.

Biến Intance:
 Là biến được khai báo trong Class và không nằm trong hàm, method hay khối
lệnh nào cả
 Có thể sử dụng ở mọi vị trí bên trong lớp chứa nó.
 Được khởi tạo khi một Object được tạo với từ khóa new
 Được khởi tạo giá trị mặc định (0, FALSE hoặc NULL)
 Được lưu trong vùng nhớ Heap

28
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Biến Static (Class Variable):


 Là biến được khai báo trong Class và nằm ngoài tất cả các hàm, method, khối
lệnh. Và được khai báo cùng với từ khóa static
 Có thể được sử dụng ở mọi vị trí trong class.
 Các biến khi khởi tạo mà không được gán giá trị thì sẽ được gán giá trị mặc
định (0, False, null)
 Được tạo khi chương trình chạy và hủy bỏ khi chương trình dừng.
 Thường dùng để khai báo các hằng số.
 Tất cả các đối tượng sẽ dùng chung biến này.
 Được lưu trong vùng Method Area

29
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

1.2 Literal
Là các giá trị hằng số hoặc các giá trị cố định.

Có 6 loại Literals trong Java:


 Boolean Literals: Gồm 2 giá trị true và false
 Integer: Binary, Dexima, Octal, Hexadecimal. Ví dụ 0b10101, 23, 023, 02xF
 Floating – point Literals
 Character Literals: ‘a’, ‘b’,…
 String Literals: “Do Thanh”
 Null Literals: Null

1.3 n
2. Java Datatypes and Operator
2.1 Datatypes

30
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

2.2 Operator

Operator Operator Description Example


Type
Arithmetic + Adds together two values x+y
Operators - Subtracts one value from another x-y
* Multiples two values x*y
/ Divides two values x/y
% Return division remainder x%y
++ If you use the ++ operator as a prefix like: + ++x
+var, the value of var is incremented by 1; x++
then it returns the value.
If you use the ++ operator as a postfix
like: var++, the original value of var is
returned first; then var is incremented by 1.

-- If you use the -- operator as a prefix like: --var, --x


the value of var is decremented by 1; then it x--

31
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

returns the value.


If you use the -- operator as a postfix
like: var--, the original value of var is returned
first; then var is decremented by 1.

Operator Operator Description Example


Type
Arithmetic + Adds together two values x+y
Operators - Subtracts one value from another x-y
* Multiples two values x*y
/ Divides two values x/y
% Return division remainder x%y
++ If you use the ++ operator as a prefix like: + ++x
+var, the value of var is incremented by 1; x++
then it returns the value.
If you use the ++ operator as a postfix
like: var++, the original value of var is
returned first; then var is incremented by 1.

-- If you use the -- operator as a prefix like: --var, --x


the value of var is decremented by 1; then it x--
returns the value.
If you use the -- operator as a postfix
like: var--, the original value of var is returned
first; then var is decremented by 1.

Operator Operator Description Example


Type
Assignment = Assigns values from right side operands C = A + B will

Operators to left side operand. assign value of A


+ B into C

+= Add AND assignment operator. It adds C += A is

32
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

right operand to the left operand and equivalent to C =


assign the result to left operand. C+A

-= Subtract AND assignment operator. It C -= A is


subtracts right operand from the left equivalent to C =
operand and assign the result to left C–A
operand.

*= Multiply AND assignment operator. It C *= A is


multiplies right operand with the left equivalent to C =
operand and assign the result to left C*A
operand.

/= Divide AND assignment operator. It C /= A is


divides left operand with the right equivalent to C =
operand and assign the result to left C/A
operand.

%= Modulus AND assignment operator. It C %= A is


takes modulus using two operands and equivalent to C =
assign the result to left operand. C%A

<<= Left shift AND assignment operator. C <<= 2 is same as


C = C << 2

>>= Right shift AND assignment operator. C >>= 2 is same as


C = C >> 2

&= Bitwise AND assignment operator. C &= 2 is same as


C=C&2

^= Bitwise exclusive OR and assignment C ^= 2 is same as


operator. C=C^2

|= Bitwise inclusive OR and assignment C |= 2 is same as C


operator. =C|2

Operato Operator Description Example


r Type
Comparison == Checks if the values of two operands (A == B) is not

Operators are equal or not, if yes then condition true.


becomes true.
(Example:
33
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

!= Checks if the values of two operands (A != B) is true.


are equal or not, if values are not equal
then condition becomes true.
> Checks if the value of left operand is (A > B) is not
greater than the value of right operand, true.
if yes then condition becomes true.
< Checks if the value of left operand is (A < B) is true.
less than the value of right operand, if
A=10, B=20) yes then condition becomes true.
>= Checks if the value of left operand is (A >= B) is not
greater than or equal to the value of true.
right operand, if yes then condition
becomes true.
<= Checks if the value of left operand is (A <= B) is true.
less than or equal to the value of right
operand, if yes then condition becomes
true.

Operato Operator Description Example


r Type
&& Returns true if both statememts are true (A && B) is
Logical
Operators false
(Example: || Returns true if one of the statememts is true (A || B) is true
A=10, ! Reverse the resuult, returns false if the !(A && B) is
B=20) result is true true

Operato Operator Description Example


r Type
Assignment & Binary AND Operator copies a bit to (A & B) will
Operators the result if it exists in both operands. give 12 which is
(Example 0000 1100
A = 0011 | Binary OR Operator copies a bit if it (A | B) will give
34
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

1100; exists in either operand. 61 which is 0011


B = 0000 1101
1101) ^ Binary XOR Operator copies the bit if (A ^ B) will give
it is set in one operand but not both. 49 which is 0011
0001
~ Binary Ones Complement Operator is (~A ) will give -
unary and has the effect of 'flipping' 61 which is 1100
bits. 0011 in 2's
complement form
due to a signed
binary number.
<< Binary Left Shift Operator. The left A << 2 will give
operands value is moved left by the 240 which is 1111
number of bits specified by the right 0000
operand.
>> Binary Right Shift Operator. The left A >> 2 will give
operands value is moved right by the 15 which is 1111
number of bits specified by the right
operand.
>>> Shift right zero fill operator. The left A >>>2 will
operands value is moved right by the give 15 which is
number of bits specified by the right 0000 1111
operand and shifted values are filled
up with zeros.

Conditional Operator(ternary operator)


Variable_x = (expression) ? value if true : value if false
Thứ tự thực hiện phép toán
Category Operator Associativity
Postfix expression++ expression-- Left to right
Unary ++expression --expression +expression Left to right
-expression ~ !
Multiplicative */% Right to left
Additive +- Left to right
Shift << >> >>> Left to right

35
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Relational < > <= >= instanceof Left to right


Equality == != Left to right
Bitwise AND & Left to right
Bitwise XOR ^ Left to right
Bitwise OR | Left to right
Logical AND && Left to right
Logical OR || Left to right
Conditional ?: Right to left
Assignment = += -= *= /= %= ^= |= <<= >>= >>>= Right to left

2.3 n
3. Input & Output
3.1 Input
Lấy input bằng cách sử dụng đối tượng Scanner:

import java.util.Scanner;

Sau đó tạo 1 đối tượng của Scanner và dùng nó để lấy dữ liệu từ người dùng.

Scanner input = new Scanner(System.in);

Câu lệnh sau dùng để lấy dữ liệu từ người dùng:

int number = input.nextInt();

36
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

3.2 Output
Dùng các lệnh println(), print() và printf() trong thuộc tính out của class system:
 print() – in chuỗi bên trong dấu ngoặc kép.
 println()- in chuỗi bên trong dấu ngoặc kép giống như hàm print(). Sau đó con
trỏ di chuyển đến đầu dòng tiếp theo.
 printf()- cung cấp định dạng chuỗi (tương tự như printf trong lập trình C/C ++).

3.3 n
4. Java expression, block and Comment
5. Keyword in Java
5.1 Từ khóa static
Khi kết hợp cùng với biến thì biến đó được gọi là biến static (Như đã trình bày ở trên)
và biến đó chỉ lấy bộ nhớ một lần trong Method Area tại thời gian tải Class đó.
Khi kết hợp cùng với Method thì Method đó được gọi là Method static hoặc phương
thức lớp. Nó tồn tại độc lập với Object và có thể được gọi thẳng từ tên của class. Nếu ta

37
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

gọi phương thức static thông qua Object thì phương thức đó chỉ dùng Object để xác định
đang gọi class nào chứ nó không biết (Có thông tin) về Object cụ thể đó.

Method static thì chỉ gọi được các biến static, Method Static.
Static Method thì không thể bị ghi đè (@Override)

5.2 Từ khóa public, protected, default, private

38
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Public Access Modifier là có thể truy cập ở bất cứ đâu. Public Access Modifier là có
thể truy cập ở bất cứ đâu. Tuy nhiên, nếu lớp public chúng ta đang cố gắng truy cập là
trong một package khác, thì lớp public này vẫn cần được import trước khi truy cập.
Các method, biến và constructor khi được khai báo private thì chỉ có thể được truy
cập trong chính lớp được khai báo đó. Các method, biến và constructor khi được khai báo
private thì chỉ có thể được truy cập trong chính lớp được khai báo đó. Các biến được khai
báo private có thể được truy cập bên ngoài lớp nếu như có tạo phương thức public getter
cho biến đó tại lớp đó.
Protected Access Modifier là có thể truy cập bên trong package và bên ngoài package
nhưng chỉ thông qua tính kế thừa. Protected Access Modifier không thể áp dụng cho lớp
và interface.
Khi không sử dụng bất cứ Modifier nào, thì theo mặc định nó được xem như là
default. Default Modifier là chỉ có thể truy cập bên trong package.

Qui tắc cần lưu ý và bắt buộc:


 Các phương thức được khai báo public trong một lớp cha cũng phải là public
trong tất cả lớp con.
 Các phương thức được khai báo protected trong một lớp cha phải hoặc là
protected hoặc public trong các lớp con; chúng không thể là private.

39
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Các phương thức được khai báo mà không có điều khiển truy cập (không sử
dụng modifier nào) có thể được khai báo private trong các lớp con.
 Các phương thức được khai báo private không được kế thừa.
 Trong Class thông thường, khi khai báo các biến và Method thì mặc định là
default.
5.3 Final, Finalize, Finally
5.3.1. Final (Là một từ khóa)
Từ khóa final: Không thể thay đổi được giá trị của biến, phương thức hay class được
khai báo cùng với biến final.
Biến final: Không thể thay đổi giá trị của biến final (nó sẽ là hằng số).

Phương thức final: Không thể ghi đè phương thức final, và có thể được kế thừa

40
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Lớp final: Không thể kế thừa lớp final.

Biến final trống: Là biến final mà không được khởi tạo tại thời điểm khai báo. Ta có
thể khởi tạo nó thông qua một constructor.

41
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Biến static final trống: Là một biến final mà không được khởi tạo tại thời điểm khai
báo. Ta có thể khởi tạo qua một static constructor.

5.3.2. Finalize (Là một Method)


Phương thức finalize() là một Method đặc biệt được cài đặt sẵn cho các Class. Trình
dọn dẹp hệ thống sẽ gọi Method này trước khi hủy một đối tượng. Vì vậy việc cài đặt
một số thao tác giải phóng, dọn dẹp vùng nhớ đã cấp phát cho các đối tượng dữ liệu trong
phương thức finalize() sẽ giúp cho người lập trình chủ động kiểm soát tốt quá trình hủy
đối tượng thay vị giao cho trình dọn dẹp hệ thống tự động. Đồng thời việc cài đặt trong
phương thức finalize() sẽ giúp cho bộ nhớ được giải phóng tốt hơn, góp phần cải tiến tốc
độ chương trình.
5.3.3. Finally (Là một Block)
Khối lệnh finally trong java được sử dụng để thực thi các lệnh quan trọng như đóng
kết nối, đóng các stream,...
Khối lệnh finally trong java luôn được thực thi cho dù có ngoại lệ xảy ra hay
không hoặc gặp lệnh return trong khối try.
5.4 n
6. Java if…else
Cú pháp:
if (condition) {
42
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

// block of code to be executed if the condition is true


}

if (condition) {
// block of code to be executed if the condition is true
} else {
// block of code to be executed if the condition is false
}

if (condition1) {
// block of code to be executed if condition1 is true
} else if (condition2) {
// block of code to be executed if the condition1 is false and condition2 is true
} else {
// block of code to be executed if the condition1 is false and condition2 is false
}

7. Switch statement
switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}

8. Loop

43
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

8.1. Vòng lặp while; do-while


while (condition) {
// code block to be executed
}

do {
// code block to be executed
}
while (condition);
8.2. Vòng lặp for
for (statement 1; statement 2; statement 3) {
// code block to be executed
}
Giải thích:
 Statement 1 is executed (one time) before the execution of the code block.
 Statement 2 defines the condition for executing the code block.
 Statement 3 is executed (every time) after the code block has been executed.
8.3. For-Each Loop
Chỉ sử dụng để lặp qua các phần tử của một mảng
for (type variableName : arrayName) {
// code block to be executed
}
Ví dụ:
String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
for (String i : cars) {
System.out.println(i);
}
8.4. n
9. Array
Khai báo và khởi tạo:
44
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Ví dụ:

10. String, StringBuffer, String Builder


10.1. String
Khai báo và ví dụ:

45
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Các Method của String

Method Description Return


Type
charAt() Returns the character at the specified index char
(position)
codePointAt() Returns the Unicode of the character at the specified int
index
codePointBefore() Returns the Unicode of the character before the int
specified index
codePointCount() Returns the number of Unicode values found in a int
string.
compareTo() Compares two strings lexicographically int
compareToIgnoreCas Compares two strings lexicographically, ignoring int
e() case differences
concat() Appends a string to the end of another string String
contains() Checks whether a string contains a sequence of boolean
characters
contentEquals() Checks whether a string contains the exact same boolean
sequence of characters of the specified
46
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

CharSequence or StringBuffer
copyValueOf() Returns a String that represents the characters of the String
character array
endsWith() Checks whether a string ends with the specified boolean
character(s)
equals() Compares two strings. Returns true if the strings are boolean
equal, and false if not
equalsIgnoreCase() Compares two strings, ignoring case considerations boolean
format() Returns a formatted string using the specified locale, String
format string, and arguments
getBytes() Encodes this String into a sequence of bytes using byte[]
the named charset, storing the result into a new byte
array
getChars() Copies characters from a string to an array of chars void
hashCode() Returns the hash code of a string int
indexOf() Returns the position of the first found occurrence of int
specified characters in a string
intern() Returns the canonical representation for the string String
object
isEmpty() Checks whether a string is empty or not Checks
whether a string is empty or not boolean
lastIndexOf() Returns the position of the last found occurrence of
specified characters in a string int
length() Returns the length of a specified string int
matches() Searches a string for a match against a regular boolean
expression, and returns the matches
offsetByCodePoints( Returns the index within this String that is offset int
from the given index by codePointOffset code points
regionMatches() Tests if two string regions are equal boolean
replace() Searches a string for a specified value, and returns a String
47
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

new string where the specified values are replaced


replaceFirst() Replaces the first occurrence of a substring that String
matches the given regular expression with the given
replacement
replaceAll() Replaces each substring of this string that matches String
the given regular expression with the given
replacement
split() Splits a string into an array of substrings String[]
startsWith() Checks whether a string starts with specified boolean
characters
subSequence () Returns a new character sequence that is a CharSe
subsequence of this sequence quence
substring() Returns a new string which is the substring of a String
specified string
toCharArray() Converts this string to a new character array char[]
toLowerCase() Converts a string to lower case letters String
toString() Returns the value of a String object String
toUpperCase() Converts a string to upper case letters String
trim() Removes whitespace from both ends of a string String
valueOf() Returns the string representation of the specified String
value
Trong java đối tượng string là bất biến(immutable). Bất biến có nghĩa là không thể
thay đổi.
public class Testimmutablestring {
public static void main(String args[]) {
String s = "Hello";
s.concat(" Java"); //phương thức concat() để nối thêm chuỗi vào đuôi chuỗi
s.
System.out.println(s); //sẽ chỉ in ra "Hello" vì các chuỗi này là đối tượng
không thể thay đổi.
48
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

}
}
Lưu ý: Trong String, khi so sánh 2 String, equal() và “==” sẽ có thể cho ra kết quả
khác nhau. Do đó, khi dùng so sánh nội dung 2 String, ta dùng equal()
10.2. String Buffer
Trong java, lớp StringBuffer được sử dụng để tạo chuỗi có thể thay đổi (mutable). Lớp
StringBuffer trong java tương tự như lớp String ngoại trừ nó có thể thay đổi.
Là một Class đồng bộ => Khi sử dụng sẽ là một Thread safe.
Do là đồng bộ nên tốc độ sẽ chậm hơn
10.3. StringBuilder
Trong java, lớp StringBuilder được sử dụng để tạo chuỗi có thể thay đổi (mutable).
Lớp StringBuilder trong java tương tự như lớp StringBuffer ngoại trừ nó không đồng
bộ(non-synchronized).
Là một Class không đồng bộ => Khi sử dụng sẽ là một Thread Unsafe. Do là không
đồng bộ nên tốc độ sẽ nhanh hơn
11. n

49
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 4: Hướng đối tượng OOP


1. Giới thiệu
Là lập trình hướng vào đối tượng chứ không phải hướng vào thủ tục như lập trình
hướng thủ tục.
Lợi ích:
 Phát triển và bảo trì dễ dàng
 Có tính năng ẩn dấu thông tin
 Có khả năng mô phỏng sự kiện thực tế hiệu quả hơn

2. Tính trừu tượng (Abstraction)


4.1 Định nghĩa trừu tượng và giai đoạn thiết kế
Trừu tượng tức là hình dung ra đối tượng, nó chỉ là một bản thiết kế thô, biết chức
năng của nó nhưng không biết nó hoạt động như nào.
Ví dụ:
 Xe máy là đối tượng A, Người dùng là đối tượng B. Chìa khóa chính là
Method. Khi ta dùng thì ta (Đối tượng B) chỉ biết chìa khóa dùng như thế nào
để mở máy xe chứ không biết là bên trong xe (Đối tượng A) thì chìa khóa
(Method) hoạt động, kết nối đến các bộ phận của xe ra sao. Lúc này ta nói chìa
khóa của đối tượng A trừu trượng so với đối tượng B.
 Tương tự, khi ta gọi hàm println, hay gọi hàm tính diện tích thì ta chỉ biết hàm
đó dùng để in ra màn hình hay tính diện tích chứ không biết trong các hàm đó
thì sử dụng các biến nào, tính toán, hoạt động ra sao. Lúc này ta nói các hàm
này là trừu tượng so với người sử dụng.

4.2 Giai đoạn triển khai


Tức là giai đoạn triển khai các thiết kế.
Abstract là một từ khóa dùng cho tính trừu tượng với đặc điểm là không cho truy cập
chỉnh sửa dữ liệu:
 Không thể được khai báo, sử dụng cùng các từ khóa: final, private, static
50
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core


Abstract class: Hiểu đơn giản là khai báo Class cùng từ khóa abstract. Một Abstract
class khi đi một mình(không có class con) thì không thể tạo một đối tượng. Các Method
của Abstract class chỉ được truy cập thông qua một lớp con (Một đối tượng được tạo từ
lớp con). Abstract Class có thể không chứa bất kỳ một Abstract Method nào.

Abstract method: Hiểu đơn giản là khai báo method cùng từ khóa abstract ở lớp cha
và được định nghĩa ở lớp con. Abstract method phải được khai báo bên trong một
Abstract Class

51
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Interface: Hiểu đơn giản là một tập hợp các Method chỉ được khai báo, với tên của
tập hợp được khai báo cùng từ khóa interface. Các Class sẽ thực hiện định nghĩa (triển
khai) các method đó. Interface là một kiểu Add-on, hợp đồng với một Class. Interface
mặc định là Public

4.3 So sánh giữa Abstract Class và Interface

Abstract Class Interface


52
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Có phương thức Abstract và phương thức Các phương thức luôn luôn được hiểu là
non-Abstract (Có thân hàm). Abstract. (Nếu không có từ khóa static).
Do đó, khi một interface1 extends một
interface2 thì interface2 không được
override lại với thân hàm.
Access Modifor cho Các biến và Method Access Modifor: Chỉ có public cho các
(Không phải Abstract): như Class thông biến.Các biến mặc định là static final.
thường. Nếu không có Modifor nào thì sẽ (VD: int a;)
mặc định là default Java 8 có thêm default, static cho Method,
lúc này Method được phép có thân hàm.
Java 9 có thêm private cho các static
Method
Access Modifor của các Abstract Method Mức truy cập của các phương thức
có thể kết hợp cùng là public hoặc Abstract có thể kết hợp cùng là public.
protected. Nếu không có Access Modifor Nếu không có Access Modifor nào đi
nào đi cùng Abstract thì sẽ mặc định cùng Abstract thì sẽ mặc định public.
public. Abstract không thể đi cùng static.
Không hỗ trợ đa kế thừa =>Sử dụng khi Có hỗ trợ đa kế thừa =>Sử dụng khi một
một nhóm đối tượng có cùng bản chất nhóm đối tượng không có cùng bản chất
(ý nói cùng bản chất ở đây là chỉ các nhưng cùng hành động.
Method không phải Abstract)
Có các biến final, non-final, static, non- Chỉ có các biến static final.
static.

Có thể implements một hoặc nhiều Không thể cài đặt nội dung của Abstract
interface và chỉ có thể extends một class nhưng có thể extends một hoặc
Abstract Class khác. nhiều interface khác.
Ví dụ: Ví dụ:
public class A implements C,D {...} //Where A is public interface C extends A,B {...} //Where
a Class and C and D are interfaces A, B and C are Interfaces

53
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Class nào kế thừa Abstract Class thì phải Abstract Class nào implements interface
triển khai toàn bộ các Abstract Method thì không nhất thiết phải triển khai toàn
của nó. bộ các Abstract Method của Interface đó.
Còn nếu là Class bình thường khi
implements interface thì nhất thiết phải
triển khai toàn bộ các Abstract Method.

Có thể dùng Constructor Không thể dùng Constructor


Đều có tính kế thừa và không thể tạo một biến kiểu interface hoặc abstract class.
Khi đi một mình thì đều không thể tạo được đối tượng.
Tạo qua một lớp ẩn danh Anonymous Class: Khi ở trong một class khác mà muốn tạo
đối tượng kiểu của AbstractClass để sử dụng thì chỉ cần triển khai những Abstract
Method public hoặc protected (Nếu class đó ở bên ngoài package. Nếu ở bên trong thì
phải triển khai tất cả Abstract Method). Còn muốn tạo đối tượng Interface thì cũng phải
triển khai toàn bộ các Method của nó.

4.4 N
3. Tính đóng gói (Encapsulation)
Là gói hết dữ liệu, chức năng vào. Có thể đạt được đóng gói nhờ Aceess Modifor
Mục đích: Khả năng che dấu dữ liệu, không cho truy cập, sửa đổi từ bên ngoài.
Cách thực hiện:
 Khai báo tất cả các biến, method là private
 Khai báo và tạo ra các hàm để nhận và hiển thị dữ liệu.

54
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

55
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Lưu ý: Có Trừu tượng thì sẽ có đóng gói. Nhưng có đóng gói thì chưa chắc có trừu
tượng. Hàm set() và Get() không phải là trừu tượng do người dùng đã biết hàm này làm
như thế nào.
4. Tính kế thừa (Inheritance)
Một class (Class con: subclass) kế thừa các thuộc tính và method của một class khác
(Class cha: superclass). Để thể hiện tính kế thừa thì bắt buộc cả 2 class phải có quan hệ
cha-con
Một lớp chỉ có thể kế thừa tối đa một lớp khác. Để có thể đa kế thừa, ta sử dụng
interface(Tính trừu tượng)
Để kế thừa, sử dụng từ khóa extends.

Từ khóa super: Dùng để truy cập (khởi tạo) giá trị trực tiếp của instance variable,
method của lớp cha từ lớp con. Hoặc cũng có thể dùng để gọi parent class constructor.

56
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Lưu ý: Super() được trình biên dịch tự động thêm vào Class Constructor nếu không có
super() hoặc this.

Để sử dụng lại tất cả các thuộc tính, phương thức, ta sẽ sử dụng parent class
constructor từ lớp con => Sử dụng lại class constructor của lớp cha.

57
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

5. Tính đa hình (Polymorphism)


Tức là có thể thực hiện một hành động bằng nhiều cách khác nhau.
Đa hình gồm 2 loại: Đa hình runtime, Đa hình compiler. Kiểu đa hình nào lại phụ
thuộc vào cách gọi các Method.
Đa hình compile time (static polymorphism) là quá trình gọi phương thức thông qua
class.
Đa hình runtime là quá trình gọi phương thức thông qua đối tượng được tạo.

5.1 Đa hình lúc thực thi (Đa hình runtime):


 Áp dụng khi 2 lớp kế thừa nhau.
 Method ở lớp con Override lại Method ở lớp cha

58
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Gọi một phương thức ở lớp cha thông qua 1 đối tượng được tạo ở lớp con. Tức
là ta tạo một biến reference kiểu của lớp cha trỏ đến đối tượng của lớp con.
 Gọi lại Method đó.
 Biến reference này có thể truy cập tất cả các Method và thuộc tính của lớp cha.
Với những Method nào đã được ghi đè ở lớp con thì khi gọi Method đó thì sẽ
gọi của lớp con. Biến Reference này không thể truy cập các Method và thuộc
tính của lớp con.

Ở dòng lệnh 20, Tạo 2 đối tượng lần lượt là: PolymorphismSubClass() và
PolymorphismSuperClass(), lưu trong Heap. Hai đối tượng này có địa chỉ bắt đầu
trùng nhau. Biến Ref1 sẽ chỉ đến địa chỉ bắt đầu này. Biến Ref do có kiểu là của
PolymorphismSuperClass nên nó chỉ có thể truy cập các Method và thuộc tính của
PolymorphismSuperClass mà không thể truy cập các Method và thuộc tính của
PolymorphismSubClass.
? Tại sao không khai báo:
PolymorphismSubClass Ref1 = new PolymorphismSubClass();
Vì ở đây mình chỉ muốn biến RefSub1 truy cập các Method của SuperClass cùng với
những Method đã được ghi đè ở SubClass chứ không muốn nó truy cập đến những
Method khác của SubClass.
Ứng dụng của đa hình run-time (chủ yếu dùng interface):
 Giảm sự phụ thuộc giữa 2 Class
 Sử dụng trong hệ thống thư viện giúp gọi lại một hàm trong thư viện.
Ví dụ:
59
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Đầu tiên ta khai báo 1 Interface với 1 Abstract Method:


public interface InterTest {
public int Square(int a, int b);
}
Sau đó, ta khai báo lại một Class Implement lại Interface đó:
public class ClassInterface implements InterTest{
public void ClassInterMethod1()
{
System.out.println("ClassInterface: ClassInterMethod1");
}
@Override
public int Square(int a, int b) {
System.out.println("Dien tich hinh chu nhat: " + a*b);
return a*b;
}
}
Tiếp theo, ta tạo một Class sử dụng các hàm của Interface:
public class Test{
public int var1;
public int var2;
int show(InterTest a)
{
return a.Square(var1, var2);
}

public static void main(String[] args) {


InterTest test1 = new ClassInterface(); // Da hinh runtime
Test test2 = new Test();
test2.var1=8;
test2.var2 =10;
int c = test2.show(test1); // CallBack Funcion
}
}
Kết quả:

Các dạng đa hình runtime:


 Một Class extends lại 1 Class khác với @override
 Class extends Abstract Class với @override.
 Class implements lại 1 interface

5.2 Đa hình lúc biên dịch (Đa hình compiler hay static polymorphism):
60
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Gọi trực tiếp một phương thức ở lớp này thông qua tên của lớp khác.
Không nhất thiết hai lớp phải kế thừa nhau thì mới có đa hình biên dịch.

5.3 Overloading và Overriding


Hai phương pháp hỗ trợ đa hình (Điều kiện cần để có đa hình):
 Overloading (Nạp chồng phương thức): Một lớp có các phương thức có tên
giống nhau nhưng khác nhau về kiểu dữ liệu hoặc số lượng các tham số. Cái
này là điều kiện cần cho đa hình lúc biên dịch.

 Overriding (Ghi đè phương thức): Một phương thức đã được khai báo (hoặc cả
định nghĩa) ở lớp cha. Nhưng sang lớp con được định nghĩa lại cụ thể hơn. Cái
này là điều kiện cần cho đa hình lúc thực thi.

61
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

@override: Dùng để xác định xem chúng ta đã ghi đè đúng Method ở lớp cha chưa. Nếu
chưa thì compiler báo lỗi.
5.4 n
6. n

62
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 5: Ngoại lệ Exception


1. Giới thiệu
Exception là một sự kiện xảy ra bất thường làm thay đổi luồng hoạt động bình thường
của chương trình, làm cho chương trình bị dừng hoặc tạm dừng không thực hiện.
Exception có 3 dạng là Checked Exception và UnChecked Exception, Error.
java.lang.Throwable class là một hệ thống phân cấp Exception được kế thừa bởi 2 lớp
con là Excetion và Error.

Checked Exception: Tức là các exception được kiểm tra trong quá trình biên dịch. Ví
dụ: IOException, SQLException,… Ngoại lệ này thì người dùng không thể lường trước
được.
UnChecked Exception: Tức là các exception được kiểm tra trong quá trình thực thi.
Ví dụ như các Class con của RuntimeException như ArithmeticException,

63
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

NullPointerException, ArrayIndexOutOfBoundsException,… Ngoại lệ này thì người


dùng có thể tránh được.
 Các Exception trên xuất hiện do người dùng và có thể được giải quyết bằng
chương trình.
Error: Tức là các Exception không thể giải quyết được bằng chương trình, xuất phát từ
hệ thống như OutOfMemoryError, VirtualMachineError, AssertionError, …
(?Error cũng là một ngoại lệ uncheck).
 Error xuất hiện do tài nguyên bị lỗi.
2. Try-Catch-final Block
Try-catch Giống như kiểu if-else. Tuy nhiên, khi gặp exception xảy ra trong try thì sẽ
không thoát ra khỏi chương trình và thông báo lỗi mà sẽ thực hiện khối lệnh trong catch
(Với điều kiện là catch truyền vào tham số đúng kiểu của Exception). Sau đó thoát ra
ngoài và thực hiện các câu lệnh tiếp theo

64
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Dạng đầy đủ là try-catch-finally:


try {
// Code
} catch (Exception1 e) {
// Code
} catch (Exception2 e) {
// code
} finally {
// Khối finally luôn luôn được thực thi.
// code.
}
Khối lệnh finally luôn luôn được thực thi dù cho Exception có được thực hiện hay
không

65
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Lưu ý: Các câu lệnh trong khối finally luôn được thực hiện. Khi gặp lệnh return ở các
khối try-catch thì luôn ưu tiên thực hiện khối lệnh trong finally trước rồi sau đó mới quay
trở lại thực hiện return.

66
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Kết quả:

VD2:

67
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Để không thực hiện khối lệnh finally, ta sử dụng System.exit().

3. Throw và Throws
3.1. Throw
Dùng để đưa ra một exception rõ ràng giúp người dùng dễ dàng khắc phục. Nếu chỉ
dùng mỗi throw thì khi gặp exception chương trình sẽ dừng luôn.

68
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

3.2. Throws

69
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Throws dùng để khai báo một Exception. Ở trường hợp trên, do trong hàm main có
khối try-catch để giải quyết Exception ở Method CheckAge nên chương trình ra kết quả
như ví dụ. Nếu không thì chương trình sẽ ném (throws) cho Class ArithmeticException
giải quyết.
(? Làm thế nào để ta có thể tạo một Exception như ArithmeticException)

3.3. So sánh Throw và Throws


Throw Throws
Dùng để ném ra một ngoại lệ rõ ràng Dùng để khai báo một ngoại lệ
Chủ yếu dùng để ném ra ngoại lệ do
người dùng tự định nghĩa
Dùng cho Unchecked Exception Dùng cho cả Checked, Unchecked
Exception. Nhưng thường chỉ dùng cho
Checked Exception
Sau throw là một instance. Sau throws là một hoặc nhiều Class
Trong Method thì có thể quăng ra Throws được khai báo ngay sau dấu
Exception ở bất kỳ dòng nào trong đóng ngoặc đơn của phương thức. Khi
phương thức (Kết hợp dùng try-catch để một phương thức có throw bên trong mà
bắt hoặc throws cho cái khác xử lý) không bắt lại (try – catch) thì phải ném đi
(throws) cho thằng khác xử lý.
Không thể throw nhiều exception. Có thể khai báo nhiều exceptions
throw new ArithmeticException("not public void method() throws IOException,
valid"); SQLException { }

3.4. n
n
4. Lan truyền ngoại lệ (exception propagation)
Như kiểu gọi lại các hàm.
5. Một số chú ý

70
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Về override:
 Nếu Method ở Class cha không khai báo Exception thì khi Class con kế thừa
Class cha đó, Override lại Method ở Class cha không được khai báo Checked
Exception nhưng có thể khai báo UnChecked Exception

- Class Cha A có khai báo exception B thì Class con C có thể không khai báo
Exception hoặc nếu có thì phải khai báo Class Exception là tương đương hoặc là
con của Class Exception B đã khai báo ở Class cha A, không được khai báo
Exception là Class cha của Exception B đã khai báo ở Class cha A.

71
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

- n
6. Java Custom Exception
Lưu ý là Class người dùng định nghĩa để giải quyết Exception bắt buộc phải kế thừa
Class trong hệ thống phân cấp Exception.
Class UserDefineException do nguời dùng tự định nghĩa

Class chương trình chính:

72
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Kết quả:

7. n

73
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 6: Collection
1. Giới thiệu
Collection là một Framework cung cấp các kiến trúc để lưu trữ và sử dụng một nhóm
các đối tượng.
Sơ đồ của Collection

List: Tập hợp các phần tử được sắp xếp một cách có trật tự, có thể chứa các phần tử
giống nhau.
Set: Tập hợp các phần tử mà trong tập hợp nó là duy nhất, được sắp xếp không có thứ
tự nào cả.
 Đây là kiểu lập trình hướng data
Stack và Queue:
 Stack: Chịu trách nhiệm ghi nhớ thứ tự các phần tử, không cho ta tự ý chèn
phần tử vào vị trí bất kỳ. Ta chỉ có thể chèn hoặc xóa ở đầu. (LIFO)
 Queue: Thêm phần tử vào cuối. Xóa phần tử thì sẽ xóa ở đầu (FIFO) (Hàng đợi)
Deque: Cho phép truy xuất, thêm xóa phần tử ở 2 đầu.
Map: Lưu trữ keys và values: Keys là duy nhất (Định danh), values là giá trị tùy ý do
người sử dụng đặt.
 HashMap: Keys có thể nhận giá trị 0 nhưng không được trùng lặp. Nếu lặp thì
sẽ sinh ra override. Trong đây thì các phần tử không có thứ tự nào cả
74
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 TreeMap: Nhất định Keys phải khác 0 và các phần tử duy trì thứ tự tăng dần.
Trong Set, các phần tử là duy nhất do mỗi phần tử là key trong Map. Key của Map
chính là giá trị phần tử của Set

2. List
2.1 ArrayList
ArrayList sử dụng mảng được cấp phát động để lưu trữ phần tử.
Dẫn đến ArrayList không bị giới hạn về kích thước. Sử dụng được
tất cả các thuộc tính của Interface List.
ArrayList:
- Có thể chứa các phần tử giống nhau.
- Duy trì thứ tự các phần tử. Tức là nếu 1 phần tử bị xóa thì
các phần tử khác sẽ được đẩy lên và ngược lại.
- Cho phép truy cập phần tử ngẫu nhiên qua index
- Là phương thức không đồng bộ non synchronized.
Khởi tạo một ArrayList: Có thể khởi tạo Non-generic hoặc
Generic Collection.
ArrayList list=new ArrayList();//creating old non-generic arraylist

Với cách khai báo trên thì list là một raw type => Khi thực hiện thì compiler sẽ đưa ra
thông báo uncheck hoặc unsafe.
ArrayList<String> list=new ArrayList<String>();//creating new generic arraylist
75
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần trong dấu < > được gọi là generic. Nó có thể là String, Integer, Bool, … generic
là một type-safe => Nên khai báo theo cách này.
Ví dụ:
Tạo một Class ThongTin:

Tạo một Class thực thi:

Kết quả:

76
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Iterator() và listIterator() method: Cùng trả về giá trị các phần tử. Tuy nhiên
listIterator() chỉ dùng cho các collection implements lại List. Iterator() thì dùng chung
cho các Data Structure khác.
ListIterator<String> iterator1 = arrlist.listIterator(2); //2 là index của phần tử trỏ tới
Iterator<String> iterator2 = arrlist.iterator();
Phân biệt size và size default:
 Size chính là kích thước thực sự của ArrayList. Ví dụ ArrayList chưa có phần
tử nào thì size =0;
 Size default: Kích thước vùng nhớ được cấp phát ban đầu. Kể cả có hay chưa có
phần tử nào thì vẫn được cấp phát vùng nhớ như thế.
Khi vượt quá size của vùng nhớ, chương trình sẽ tìm một vùng nhớ có kích thước lớn
hơn 50% vùng nhớ cũ. Sau đó sẽ thực hiện copy toàn bộ các phần tử cũ rồi sau đó mới
thêm phần tử mới. Do đó chỉ nên dùng khi data còn ít và ít thay đổi (Thêm phần tử,
…). Do khi chương trình chạy, để tìm vùng nhớ liên tục có kích thước như mong muốn là
rất khó, cộng thêm việc sao chép dữ liệu sẽ làm chương trình chạy lâu và dễ gây ra lỗi.
2.2 Vector (ít dùng)
Vector là một mảng động để lưu trữ các phần tử. Vector là một phương thức đồng bộ.
Vector cung cấp một khả năng truy cập an toàn. Tức là khi có nhiều thread cùng truy
cập vào một tài nguyên, giá trị dùng chung thì nó có cơ chế bảo vệ giúp cho tại một thời
điểm chỉ cho một thread hoặc method truy cập vào sửa đổi nó. Còn ArrayList và
LinkedList là không an toàn do nó không có cơ chế tự bảo vệ dữ liệu, cho phép nhiều
method cùng truy cập một lúc dẫn đến có thể làm sai khác giá trị. Để an toàn, ta chỉ nên
77
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

sử dụng khi nó chỉ có 1 thread truy cập vào hoặc ta phải xây dựng thêm cơ chế bảo vệ dữ
liệu.
2.3 LinkedList
LinkedList sử dụng danh sách liên kết kép để lưu trữ
phần tử (doubly linked list).

LinkedList(doubly linked list): sẽ dùng 2 con trỏ previous


và con trỏ next để lưu địa chỉ phần tử trước và sau nó. Hai
con trỏ này đều có kích thước là 1 word (Hiện tại trong
JVM 1 word = 4byte) lúc Compiler. Và một thành phần
nữa lưu data. Dẫn đến kích thước của LinkedList sẽ lớn hơn ArrayList. Tuy nhiên, không
giống như ArrayList, Linked xác định vị trí các phần tử nhờ con trỏ previous và con trỏ
next do đó có thể tận dụng được không gian bộ nhớ.
LinkedList:
- Có thể chứa các phần tử giống nhau
- Duy trì thứ tự các phần tử
- Truy cập đến một phần tử thì lâu hơn là ArrayList nhưng thêm, xóa (Thao tác
với data) thì nhanh hơn.
- Có thể sử dụng được các thuộc tính của Interface List, Queue hoặc Class Stack.
- Là phương thức không đồng bộ non synchronized.
Khai báo:
LinkedList<String> al=new LinkedList<String>();

Ví dụ:

78
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Kết quả:

2.4 So sánh và cách sử dụng ArrayList, LinkedList, Vector


ArrayList Vector
Synchronization Non Synchronization Synchronization
Size Tăng 50% size hiện tại nếu số Tăng 100% size hiện tại nếu số
lượng các phần tử thêm vào lượng các phần tử thêm vào vượt
79
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

vượt quá size hiện tại quá size hiện tại


Legacy Không được kế thừa Là 1 class được kế thừa
Speed Nhanh hơn do tính Non Chậm hơn do tính
Synchronization Synchronization
Iteration Dùng iterator để truy cập các Dùng cả iterator hoặc enumerator
phần tử để truy cập các phần tử

2.5 n
3. Map
Map gồm 2 thành phần chính là keys và values.
 Key dùng để định danh, mở khóa truy cập giá trị. Các Key là duy nhất.
 Value chính là giá trị truyền vào. Values có thể giống và khác nhau.

 Map dùng hàm toán học để đưa ra ánh xạ giữa 2 tập hợp key và value
3.1. HashMap
Hashing: Kỹ thuật băm. Nó sẽ chuyển đổi một chuỗi các ký tự (Text) sang một giá trị
số có độ dài cố dịnh và ngắn hơn để đại diện cho đối tượng ban đầu.
https://www.youtube.com/watch?v=c3RVW3KGIIE
Hash Code: Method thực hiện Hashing, thực hiện việc chuyển đổi trên.
Buckets: Một mảng các Node. Nó có index từ 0-15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

80
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Một Node (Phần tử trong mảng) có dạng như một danh sách liên kết đơn gồm 4 thành
phần: Key, Giá trị hash, Value, Và một con trỏ trỏ tới Node tiếp theo.
Một Node:
Key Hash Value Con trỏ Next

Nguyên lý hoạt động:


Đầu tiên ta truyền vào một Key ví dụ như “ABC”, Qua Method HashCode sẽ sinh ra
một giá trị hashing ví dụ như “123456”. Giá trị Hash này sẽ được biến đổi để rút ngắn lại
cho phù hợp với giá trị Index (nếu cần) ví dụ giá trị này thực hiện thao tác bit tạo ra một
giá trị là 2, 2 đây được tạo ra chính là vị trí mà Node này sẽ được chèn vào (Index).
Value chính là giá trị người dùng đưa vào. Nếu tại vị trí Index chưa có phần tử nào thì
con trỏ trỏ tới Node tiếp theo sẽ là NULL. Tương tự nếu tại vị trí đó đã có phần tử rồi thì
Node này sẽ được thêm vào làm Node tiếp theo của Node đã tồn tại trước đó.
Khi tìm một phần tử thì sẽ làm tương tự như quá trình sắp xếp, chỉ có điều sau khi ra
được giá trị hash và index thì sẽ đi so sánh index và giá trị hash của phần tử trong index
đó rồi nhận về giá trị.
Lưu ý trong HashMap:
 Là phương thức không đồng bộ và không an toàn
 Key là duy nhất và không được trùng lặp.
 Có thể chứa một Key Null và nhiều giá trị NULL
 Không có trật tự sắp xếp các phần tử. Tức là khi sinh ra một index thì phần tử
đó được sắp xếp vào sau Node đã có.
 Sử dụng Iterator để duyệt phần tử.

3.2. HashTable
Về Nguyên lý hoạt động tương tự như HashMap
Tuy nhiên:
 Là phương thức đồng bộ và an toàn
 Không cho phép các Keys giống nhau.
 Không cho phép chứa các Key Null và giá trị NULL
81
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Sử dụng Enumerator and Iterator để duyệt phần tử.


 Duyệt chậm hơn HashMap
3.3. LinkedHashMap
Phương thức hoạt động là sự kết hợp của HashMap và LinkedList. Do đó nó vừa sử
dụng cơ chế và đặc tính như HashMap đồng thời duy trì trật tự chèn các phần tử theo thứ
tự xác định.
3.4. TreeMap
Dầu tiên nói về cây nhị phân. Cây nhị phân.
Cây nhị phân là cây mà tại 1 nút cha chỉ có thể có tối đa 2 nút con. Giá trị đưa vào so
sánh nếu nhỏ hơn nút cha thì sẽ đặt bên trái, lớn hơn hoặc bằng nút cha thì đặt bên phải.

TreeMap cách hoạt động kết hợp của HashMap và cây nhị phân. Tuy nhiên nó không
dùng HashCode để chuyển đổi Key sang Index mà nó sử dụng thuật toán Red-Black Tree
để sắp xếp các phần tử vào các Node.
Red-Black Tree là cây tìm kiếm nhị phân tự cân bằng (BST) . Nó có các thuộc tính
sau:
 Trong Red-Black Tree, màu của nút là đỏ hoặc đen .
 Nút gốc luôn có màu đen .
 Nút màu đỏ không được có nút hàng xóm cùng màu. (Nút dưới nó)
 Tất cả các đường dẫn từ nút gốc đến nút rỗng phải chứa cùng một số lượng nút
đen.


 Cấu trúc của một nốt:
82
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Left lưu địa chỉ của nút cha. Right lưu địa chỉ của nút con. (1 Node gồm 1 con trỏ left
và 2 con trỏ right) Key là khóa định danh. Color là bit màu sắc.
Lưu ý:
 Các Key là duy nhất
 Không cho phép key là NULL nhưng có thể có nhiều giá trị là NULL.
 Là phương thức không đồng bộ
3.5. N
n
4. Set
4.1 HashSet
HashSet sử dụng bảng băm hash table để lưu trữ dữ liệu. Nó
kế thừa từ AbstractSet class and implements Set interface. Do
đó, các phần tử trong hash table là duy nhất (Do đặc tính của
Set).
Hash table lưu trữ giá trị sử dụng kỹ thuật hashing. Các
phần tử trong hash table được truy cập bằng hash code. Hash
code chính là định danh duy nhất dùng để xác định một phần
tử có giá trị duy nhất trong hash table. Do đó sẽ không xuất
hiện phần tử nào khác trong hash table có giá trị giống nó.
Đồng thời, HashSet cũng cho ta truy cập một phần tử ngẫu
nhiên do đặc tính dùng hash code để truy cập của hash table.

HashSet:
 Giá trị trong HashSet là duy nhất
 Là phương thức không đồng bộ
 Cho phép giá trị NULL

83
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Là cách tốt nhất để tìm kiếm một phần tử (Do giá trị của các phần tử là duy
nhất)
 Kích cỡ mặc định là 16 và hệ số tải là 0.75 (Tức là mặc định một hash table
chứa 16 phần tử. Khi số lượng phần tử đạt mức 0.75 thì sẽ gấp đôi dung lượng
hiện tại)
Khai báo:
HashSet<String> set=new HashSet();
Ví dụ 1:

Ví dụ 2:

84
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Kết quả:

4.2 LinkedHashSet
LinkedHashSet Class là cung cấp chức năng của LinkedList và Hashtable. Nó triển
khai interface Set.
LinkedHashSet:
- Chứa các phần tử duy nhất
- Cho phép giá trị NULL
- Sử dụng danh sách liên kết kép duy trì thứ tự các phần tử và thứ tự chèn vào
HashTable.
Khai báo:
LinkedHashSet<String> set=new LinkedHashSet();
4.3 TreeSet
TreeSet Class Class implement the Comparable interface.
TreeSet duy trì thứ tự các phần tử tăng dần. Các phần tử này được so sánh, sắp xếp
dựa vào tiêu chí của Comparable interface do người dùng định nghĩa.
4.4 n
5. ArrayDeque
ArrayDeque là 1 class triển khai interface Queue và Deque.

85
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Để triển khai stack LIFO (Last-In-First-Out) trong Java, nên sử dụng một deque thay
vì sử dụng class Stack . Class ArrayDeque thường nhanh hơn so với class Stack.
 ArrayDeque cung cấp các hàm sau có thể được sử dụng để triển khai stack.
 push() – thêm một phần tử vào đầu stack
 peek() – trả về một phần tử từ đầu stack
 pop() – trả về và xóa một phần tử ở đầu stack
Cả ArrayDeque và Class LinkedList trong Java đều triển khai Deque interface. Tuy
nhiên, có một số điểm khác biệt giữa chúng.
 LinkedList hỗ trợ phần tử không, trong khi ArrayDeque thì không.
 Mỗi nút trong LinkedList bao gồm các liên kết đến các nút khác. Dẫn
đến LinkedList cần nhiều dung lượng hơn ArrayDeque.
 Nếu triển khai cấu trúc dữ liệu queue hoặc cấu trúc dữ liệu deque thì dùng
ArrayDeque thường sẽ nhanh hơn a LinkedList.

6. PriorityQueue
PriorityQueue Class implement interface Queue. Duy trì thứ tự sắp xếp các phần tử
theo mức độ ưu tiên. Phần tử nào có mức độ ưu tiên cao hơn thì sẽ được xóa trước. Đây
là kiểu thực hiện tuần tự theo hàng đợi, là kiểu lập trình hướng sự kiện.
PriorityQueue:
 Không chứa giá trị null
 Bắt buộc khi tạo PriorityQueue phải tạo mức độ ưu tiên của đối tượng để
PriorityQueue so sánh.
 Không phải Thread an toàn.
Queue người ta hay dùng để phân tán hệ thống. Bình thường 1000 request đến chẳng
hạn nó không xử lý luôn cả 1000 mà đẩy hết vào queue xử lý dần.
7. n

86
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 7: Java 8
1. Defaut Method
Thêm từ khóa Default vào trước Method trong Interface thì Method đó được phép có
thân hàm.
2. Funcional Interfaces
Funcional Interfaces: Sử dụng từ khóa @FunctionalInterface
Đây là Interface chỉ chứa 1 Abstract Method => Giúp thuận tiện cho quá trình dùng
Lamda Expressions để implements.

3. Lamda Expressions
Là một hàm ẩn danh.
Có thể dùng để implement nhanh một Funcional Interfaces.
Cách khai báo: (Danh_sách_đối_số) -> {Khối lệnh thực hiện}.
 Danh_sách_đối_số: Có thể không có, có một hoặc nhiều đối số
 ->: Liên kết danh sách đối số và thân của biểu thức
 Khối lệnh thực hiện: Chứa các biểu thức và câu lệnh cần thực hiện.
Chú ý, Lamda Expressions không có kiểu dữ liệu trả về tường minh. Java 8 sẽ tự hiểu
và trả về kiểu giá trị tương ứng.
Ví dụ 1:

87
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Ví dụ 2:

Sẽ được viết lại với Lamda Expression như sau:

88
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Truy cập biến final và local: Các biến trong Lamda Expression là biến final hoặc
effectively final (Biến không bị thay đổi giá trị).

4. Method References
4.1 Giới thiệu
Đây là một cách viết tắt của biểu thức Lamda để gọi tới một Method được truyền vào
làm tham số mà Method đó dùng để implements một Interface.
4.2 Tham chiếu đến một Static Method
Cú pháp:
Class::staticMethod

89
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

4.3 Tham chiếu đến một instance Method của một đối tượng cụ thể
Cú pháp:
object::instanceMethod

4.4 Tham chiếu đến một instance Method của một đối tượng tùy ý với kiểu cụ thể
Cú pháp:
90
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Class::instanceMethod

4.5 Tham chiếu đến một constructor


Cú pháp:
Class::new

5. Stream API
5.1 Giới thiệu
Stream (Luồng) Bao gồm các class, interface và enum để cho phép các hoạt động kiểu
function trên các element (phần tử) của một Collection, Array trở nên dễ dàng và tối ưu
hơn. Nó thực hiện chỉ khi có yêu cầu (lazy).
Một Stream đại diện cho một chuỗi các phần tử hỗ trợ các hoạt động tổng hợp tuần tự
(sequential) và song song (parallel).
91
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Với Method withoutStream: Duyệt danh sách từ đầu để đếm các số chẵn
Với Method withStream: Thực hiện 3 công việc cùng lúc:
 stream: Danh sách các phần tử của numbers
 filter: Danh sách các phần tử chia hết cho 2
 count: Đếm các phần tử chia hết cho 2
Một số phương thức của Stream:
 stream() : trả về một stream sẽ được xử lý theo tuần tự.
 parallelStream() : trả về một Stream song song, các xử lý sau đó sẽ thực hiện
song song.
Đặc điểm:
 Stream không lưu trữ các phần tử của collection hay array. Nó chỉ thực hiện các
phép toán tổng hợp (chẳng hạn như filter() và count() mà chúng ta đã thấy
trong ví dụ trên để có được stream dữ liệu mong muốn.
 Stream không phải là một cấu trúc dữ liệu (data structure).
 Stream là immutable object. Các hoạt động tổng hợp mà chúng ta thực hiện
trên Collection, Array hoặc bất kỳ nguồn dữ liệu nào khác không làm thay đổi
dữ liệu của nguồn, chúng chỉ trả lại stream mới. Chúng ta đã thấy ở ví dụ trên
là thực hiện filter() các các số chẵn bằng cách sử dụng các hoạt động của stream
nhưng nó không thay đổi các phần tử của List numbers.

92
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Tất cả các hoạt động stream là lazy (lười biếng), có nghĩa là chúng không được
thực hiện cho đến khi cần thiết. Để làm được điều này, hầu hết các thao tác với
Stream đều return lại một Stream mới, giúp tạo một mắc xích bao gồm một loạt
các thao tác nhằm thực thi các thao tác đó một cách tối ưu nhất. Mắt xích này
còn được gọi là pipeline. Pipleline: Intermediate operations và Terminal
Operations.
 Các phần tử của luồng chỉ được truy cập một lần trong suốt vòng đời của
Stream. Giống như một Iterator, một Stream mới phải được tạo ra để duyệt lại
các phần tử của dữ liệu nguồn.
 Stream không dùng lại được, nghĩa là một khi đã sử dụng nó xong, chúng ta
không thể gọi nó lại để sử dụng lần nữa.
 Chúng ta không thể dùng index để truy xuất các phần tử trong Stream.
 Stream hỗ trợ thao tác song song các phần tử trong Collection hay Array.
Các bước thực hiện với stream:
 Tạo stream
 Thực hiện thao tác trung gian (intermediate operations). Có thể có nhiều hoạt
động trung gian.
 Thực hiện thao tác đầu cuối (terminal operation)

5.2 Ví dụ
Có thể không sử dụng, sử dụng một hoặc nhiều intermediate operations để chuyển đổi
Stream ban đầu thành những Stream mới. Mặc dù chúng ta có thể định nghĩa nhiều
intermediate operation nhưng chúng không thực thi các thao tác đó ngay lập tức, chỉ
khi terminal operation được gọi thì toàn bộ các thao tác đó mới được thực thi.
Tạo Stream:
 Tạo stream cho những kiểu primitive:
IntStream, LongStream hay DoubleStream

93
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Tạo stream từ các cấu trúc dữ liệu khác:


 Tạo stream sang các cấu trúc dữ liệu khác:
 n
Intermediate operations:
 Stream filter() giúp loại bỏ các phần tử dựa trên các tiêu chí nhất định.
 tream skip() được sử dụng để loại bỏ các phần tử n đầu tiên của Stream . Nếu
Stream này chứa ít hơn n phần tử thì luồng trống sẽ được trả lại.
 Stream limit() được sử dụng để cắt giảm kích thước của Stream. Kết quả trả về
các phần tử của Stream đã được cắt giảm để không vượt quá maxSize (tham số
đầu vào của phương thức).
 Stream map() giúp ánh xạ các phần tử tới các kết quả tương ứng.
 Stream sorted() giúp sắp xếp các phần tử theo một thứ tự xác định.
Terminal Operations (Dùng lấy kết quả từ những intermediate operations đã dịnh):
 forEach() giúp duyệt qua các phần tử của Stream.
 collect() giúp thu thập kết quả Stream sang một Collection.
 anyMatch() trả về một boolean tùy thuộc vào điều kiện được áp dụng trên
Stream dữ liệu. Phương thức này trả về true ngay khi phần tử đầu tiên thõa mãn
điều kiện, những phần tử còn lại sẽ không được kiểm tra.
 allMatch() : Phương thức này trả về true nếu tất cả phần tử đều thỏa mãn điều
kiện. Nếu một phần tử không thõa điều kiện, những phần tử còn lại sẽ không
được kiểm tra.

94
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 noneMatch() : Ngược lại với allMatch(), pương thức này trả về true nếu tất cả
phần tử đều không thõa mãn điều kiện. Nếu một phần tử thõa điều kiện, những
phần tử còn lại sẽ không được kiểm tra.
 count() trả về tổng số phần tử cho dữ liệu luồng.
 Stream.max(), Stream.max() chấp nhận đối số là một Comparator sao cho các
item trong stream có thể được so sánh với nhau để tìm tối thiểu (min) hoặc tối
đa (max).
 summaryStatistics() được sử dụng để lấy giá trị count, min, max, sum và
average với tập dữ liệu số.
 reduce() kết hợp các phần tử luồng thành một bằng cách sử dụng một
BinaryOperator.

5.3 Stream API với I/O


Hỗ trợ đọc các file vào ra đồng thời nhanh chóng
5.4 Parallel Streams (Luồng song song)
Các stream có thể là tuần tự (sequential) hoặc song song (parallel). Các thao tác trên
các stream tuần tự được thực hiện trên một luồng đơn (single thread) trong khi các phép
toán trên các stream song song được thực hiện đồng thời trên nhiều luồng (multi-thread).

95
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Cách hoạt động:

 Thường sử dụng Parallel Streams trong môi trường multi-thread khi mà chúng ta
cần hiệu suất xử lý nhanh.

5.5 Hạn chế


5.6 n
6. Collection API Enhencement
Một số cải tiến về Collections như stream, parallel stream, map, compute, …
7. Annotation
Repeating annotation – cho phép các annotation giống nhau có thể được khai báo
nhiều lần cùng một vị trí. Type Annotation – có thể được áp dụng cho bất kỳ kiểu dữ liệu
nào (Type), bao gồm: new operator, type casts, implements clauses và throws clauses.
8. Date Time API
Cung cấp một số lớp mới trong gói java.time cùng với định dạng thời gian Joda.
9. Optional
Optional trong Java 8 là một Container object, nó bao bọc (warpper) một object, object
này có thể present hoặc không. Khi object là null thì Optional trả về empty. Đặc biệt
Optional hỗ trợ lambda expression.
Là một lớp được sử dụng để hạn chế với lỗi NullPointerException trong ứng dụng
Java.

10. n
96
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Phần 8: Thread và MultiThread


1. Giới thiệu
Thread (luồng) là một tiến trình con (sub-process) thực hiện một công việc riêng biệt,
được quản lý bới JVM.
Multi-Thread (đa luồng) là một tiến trình thực hiện nhiều luồng đồng thời.
Multi-tasking (Đa nhiệm) là khả năng chạy nhiều chương trình cùng một lúc trên một
hệ điều hành => Tận dụng được tính năng của CPU.
Multi-tasking có thể đạt được nhờ:
 Dựa trên tiến trình đơn – Đa tiến trình (Multi-Process): Yêu cầu mỗi tiến trình
phải có vùng nhớ riêng biệt => Giao tiếp giữa các tiến trình có chi phí cao và
cần nhiều thời gian để chuyển từ tiến trình này sang tiến trình khác.
 Dựa trên Thread và Multi-Thread: Các luồng chia sẻ không gian bộ nhớ và tài
nguyên chung => Sự giao tiếp giữa các luồng dễ dàng hơn. => Hay được sử
dụng

Ưu điểm của đa luồng:


 Các luồng có thể dùng chung và chia sẻ tài nguyên trong quá trình chạy.
 Khi 1 luồng xảy ra ngoại lệ thì các luồng khác vẫn chạy vì các luồng là độc lập.
 Có thể thực nhiều hoạt động để tiết kiệm thời gian.
Nhược điểm của đa luồng:
 Nhiều luồng => Xử lý phức tạp
 Phức tạp trong xử lý tranh chấp bộ nhớ và đồng bộ dữ liệu

97
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Cần chú ý và cẩn thận với các luồng chết (deadlock) hay các luồng chạy mà
không làm gì cả.
Vòng đời của một Thread trong Java:

 NEW:thread vừa được khởi tạo bằng Method khởi tạo của lớp Thread nhưng
chưa được start(). Thread được tạo ra nhưng chưa được cấp phát tài nguyên
và cũng chưa chạy. Nếu lúc này mà ta gọi các Method stop, resume, suspend …
=> ngoại lệ IllegalThreadStateException.
 RUNNABLE: Sau khi gọi Method start() thì thread đã được cấp phát tài nguyên
và CPU bắt đầu xếp lịch điều phối cho thread. Ở đây, thread không thực sự luôn
chạy mà tùy vào hệ thống mà có sự điều phối CPU khác nhau.
 WAITING : Thread chờ không giới hạn cho đến khi một thread khác đánh thức
nó.
 TIMED_WAITING : Thread chờ trong một thời gian nhất định, hoặc là có một
thread khác đánh thức nó.
 BLOCKED: Đây là 1 dạng của trạng thái “Not Runnable”, là trạng thái khi
Thread vẫn còn sống, nhưng hiện tại không được chọn để chạy. Thread chờ một
monitor để unlock một đối tượng mà nó cần.
 TERMINATED : Một thread ở trong trạng thái terminated hoặc dead khi
Method run() của nó bị thoát.

98
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Chú ý: Thread trong Java là Software Thread. Và Thread trong đây chỉ có khái
niệm đồng thời (Concurence), không phải song song. Tức là tại một thời điểm thì hệ
thống sẽ xếp lịch cho m1 Thread hoạt động hoặc nhiều Thread cùng hoạt động.
2. Tạo Thread trong Java
2.1 Extends từ Class Thread
 Khai báo 1 Class mới extends Class Thread
 Override lại Method run() ở Class Thread, những gì trong Method run() sẽ được
thực thi khi thread bắt đầu chạy. Sau khi thread chạy xong tất cả các câu lệnh
trong phương thức run thì thread cũng tự hủy.
 Tạo 1 thể hiện (hay 1 đối tượng) của class ta vừa khai báo.
 Sau đó gọi phương thức start() của đối tượng này để bắt đầu thực thi luồng.

Lưu ý:
 Method run() chỉ là 1 Method giúp khai báo ra những công việc cần làm.
Method start() là Method đặc biệt để cấp phát tài nguyên cho Thread và chạy
Method run() ở Thread mới. Nếu không gọi start() mà chỉ gọi Method run() thì
nó vẫn được chạy trên Thread chính như những Method khác.
 Một Thread chỉ có thể start 1 lần. Nếu không thì sinh ra Exception
IllegalThreadStateException

2.2 Implement từ Interface Runable


 Khai báo 1 Class mới implements từ Interface Runnable

99
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 Hiện thực Method run() ở Class này, những gì trong Method run() sẽ được thực
thi khi Thread bắt đầu chạy. Sau khi Thread chạy xong tất cả các câu lệnh trong
Method run thì Thread cũng tự hủy.
 Tạo 1 Object của Class ta vừa khai báo. (VD : Tên đối tượng là r1)
 Tạo Object của Class Thread bằng Method khởi tạo: Thread(Runnable target)
 Runnable target: Là 1 Object thuộc Class được implements từ giao diện
Runnable.
 Ví dụ: Thread t1 = new Thread(r1);
 Gọi phương thức start() của đối tượng t1.

 Cách này thường được sử dụng:


 Không cần tạo 1 class extends Class Thread.
 Sử dụng hiệu quả và đơn giản cùng với Thread Pool.

2.3 Kết hợp tạo Thread với Lamda Expressions


Ví dụ 1:

100
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

2.4 n
3. Process Schedulers
4. Process Table and Process Control Block (PCB)
5. Interrupt
6. Các Method của Thread (thường được sử dụng)
suspend() : tạm dừng hoạt động của 1 Thread nào đó bằng các ngưng cung cấp CPU
cho Thread này. Để cung cấp lại CPU cho Thread ta sử dụng Method resume(). Lưu ý: ta
không thể dừng ngay hoạt động của Thread bằng Method này. Method suspend() không
dừng ngay tức thì hoạt động của Thread mà sau khi Thread này trả CPU về cho hệ điều
hành thì không cấp CPU cho Thread nữa.
resume() : Cho Thread chạy lại khi Thread bị dừng do Method suspend() bên trên.
Method này sẽ đưa Thread vào lại lịch điều phối CPU để Thread được cấp CPU chạy lại
bình thường.
stop() : Kết thúc Method run() bằng cách ném ra 1 ngoại lệ ThreadDeath=> Cưỡng
chế Thread kết thúc. Nếu trước khi gọi stop() mà Thread đang nắm giữa 1 đối tượng nào

101
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

đó hoặc 1 tài nguyên nào đó mà Thread khác đang chờ thì có thể dẫn tới việc xảy ra
deadlock.
destroy() : dừng hẳn Thread.
isAlive() : Kiểm tra xem Thread còn active hay không. Method sẽ trả về true nếu
Thread đã được start() và chưa rơi vào trạng thái dead. Nếu Method trả về false thì
Thread đang ở trạng thái “New Thread” hoặc là đang ở trạng thái “Dead”
yeild() : Hệ điều hành đa nhiệm sẽ phân phối CPU cho các tiến trình, các Thread theo
vòng xoay. Mỗi Thread sẽ được cấp CPU trong 1 khoảng thời gian nhất định, sau đó trả
lại CPU cho hệ điều hành (HĐH), HĐH sẽ cấp CPU cho Thread khác. Các Thread sẽ
nằm chờ trong hàng đợi Ready để nhận CPU theo thứ tự. Java có cung cấp cho chúng ta 1
Method khá đặc biệt là yeild(), khi gọi Method này Thread sẽ bị ngừng cấp CPU và
nhường cho Thread tiếp theo trong hàng chờ Ready. Thread không phải ngưng cấp CPU
như suspend mà chỉ ngưng cấp trong lần nhận CPU đó.
sleep(long) : tạm dừng Thread trong một khoảng thời gian millisecond.
join() : thông báo rằng hãy chờ thread này hoàn thành rồi thread cha mới được tiếp tục
chạy.
join(long) : Thread cha cần phải đợi millisecond mới được tiếp tục chạy, kể từ lúc gọi
join(long). Nếu tham số millis = 0 nghĩa là đợi cho tới khi Thread này kết thúc.
getName() : Trả về tên của thread.
setName(String name) : Thay đổi tên của thread.
getId() : Trả về id của thread.
getState(): trả về trạng thái của thread.
currentThread() : Trả về tham chiếu của thread đang được thi hành.
getPriority() : Trả về mức độ ưu tiên của thread.
setPriority(int) : Thay đổi mức độ ưu tiên của thread.
isDaemon() : Kiểm tra nếu thread là một Thread Daemon.
setDaemon(boolean): xác định thread là một Thread Daemon hay không.
interrupt() : làm gián đoạn một Thread trong java. Nếu thread nằm trong trạng thái
sleep hoặc wait, nghĩa là sleep() hoặc wait() được gọi ra. Việc gọi Method interrupt() trên
thread đó sẽ phá vỡ trạng thái sleep hoặc wait và ném ra ngoại lệ InterruptedException.

102
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Nếu thread không ở trong trạng thái sleep hoặc wait, việc gọi Method interrupt() thực
hiện hành vi bình thường và không làm gián đoạn thread nhưng đặt cờ interrupt thành
true.
isInterrupted() : kiểm tra nếu thread đã bị ngắt.
interrupted() : kiểm tra nếu thread hiện tại đã bị ngắt.

7. ThreadId, ThreadName, Priority


ThreadId: định danh của luồng, nó dùng để phân biệt với các luồng khác cùng tiến
trình hoặc cùng tập luồng. Đây là thông số mà máy ảo java tự tạo ra khi ta tạo luồng nên
ta không thể sửa đổi cũng như áp đặt thông số này khi tạo luồng. Nhưng ta có thể lấy
được nó thông qua phương thức getId() của lớp Thread
ThreadName: tên của luồng, đây là thuộc tính mà ta có thể đặt hoặc không đặt cho
luồng. Nếu ta không đặt cho luồng thì máy ảo java sẽ tự đặt với quy tắc sau: “Thread-” +
Thứ tự luồng được tạo ra, bắt đầu từ 0.
Priority:
 Mỗi Thread có 1 độ ưu tiên nhất định. Đây sẽ là thông số quyết định mức ưu
tiên khi cấp phát CPU cho các Thread.
 Đặt độ ưu tiên cho 1 Thread với Method: void setPriority(int newPriority)
 int newPriority : Là giá trị từ 1 đến 10.
 Java có định nghĩa sẵn 3 mức ưu tiên chuẩn như sau:
Thread.MIN_PRIORITY (giá trị 01)
Thread.NORM_PRIORITY (giá trị 05)
Thread.MAX_PRIORITY (giá trị 10)
 Để lấy độ ưu tiên của 1 luồng, ta dùng Method: int getPriority()

8. Xử lý Exception cho Thread


Method Thread.setDefaultUncaughtExceptionHandler() thiết lập mặc định xử lý khi
luồng đột ngột chấm dứt do một ngoại lệ còn tự do, mà không có xử lý khác đã được xác
định cho luồng đó.

103
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

9. Các loại Thread trong Java, Thread Pool


9.1 Force Threads và Background Threads
Force Thread (User Threads)
User Threads là một Thread, thời gian sống không phụ thuộc vào thread khác.

Background Thread (Deamon Threads)


 Deamon Threads là một Thread mà thời gian sống của nó phụ thuộc vào Force
Thread và Thread main. Chỉ cần 1 Force Thread vẫn còn thì nó vẫn chạy.
 Sử dụng setDeamon(boolean) để sét một Thread là Deamon hoặc không. Chỉ
có thể gọi hàm setDeamon(boolean) khi thread chưa được chạy. Điều đó có
nghĩa là khi thread đã chạy bạn không thể chuyển Thread từ non-deamon (User
Threads) sang deamon và ngược lại.
 Thread Deamon quan trọng của Java đó là luồng gom rác (Garbage
Collection Thread), nghĩa là gom các tài nguyên không còn sử dụng để giải
phóng bộ nhớ. Khi tất cả các Thread người dùng không còn hoạt động nữa
Garbage Collection Thread cũng bị dừng theo.
Lưu ý: Khi một Thread mới được tạo ra, nó được thừa hưởng đặc tính deamon từ
Thread cha. Như vậy khi bạn tạo một Thread trong hàm main của 1 class (nó vốn là
Thread non-deamon), vì vậy thread tạo ra mặc định cũng là non-deamon. Nếu bạn tạo
một Thread mới trong một Thread Deamon, mặc định nó cũng sẽ là Deamon.
Kiểm tra một Thread có phải là Deamon hay không ta sử dụng:
Tên_Thread.isDeamon();
Kết quả trả về là true nếu đó là Daemon Thread và ngược lại.

9.2 Thread Pool


Mỗi Thread đảm nhiệm một nhiệm vụ xác định. Tuy nhiên, sau khi thực hiện xong
nhiệm vụ đó, nếu ta không làm gì thì Thread đó vẫn tồn tại, vẫn chiếm tài nguyên của hệ
thống nhưng lại không thực hiện nhiệm vụ nào cả => Gây lãng phí tài nguyên của hệ
thống.

104
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Để giải quyết vấn đề trên, ta sử dụng Thread Pool. Với Thread pool, khi một Thread
làm xong một nhiệm vụ thì nó sẽ được giao một nhiệm vụ mới.

Task Submitters submit danh sách các nhiệm vụ cần thực hiện được
Executor Service là một đối tượng gồm 2 thành phần là Task Queue và Thread Pool:
 Task Queue là một Reference đến một Collection dạng Queue. Cái này có chức
năng xếp các task cần giải quyết vào hàng đợi.
 Thread Pool là một Reference đến một Collection dạng ArrayList. Cái này có
nhiệm vụ xem Thread nào đã thực hiện xong nhiệm vụ thì đẩy task mới vào.
Tất cả các Thread trong Thread pool là 1 Force Thread.

9.3 Cách khai báo và sử dụng Thread Pool.


9.3.1 Executor, Executors, ExecutorService,
Executors Class cung cấp các Method để khởi tạo cấu hình cho Executor,
ExecutorService, ScheduledExecutorService, ThreadFactory, and Callable
Executor Interface chứa một Method execute() để submit các Runnable instances để
thực thi.
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(() -> System.out.println("Hello World"));
ExecutorService Interface chứa nhiều Method để kiểm soát việc thực hiện các task và
kết thúc các Thread.
ExecutorService executorService = Executors.newFixedThreadPool(10); // 10 Thread
Future<String> future = executorService.submit(() -> "Hello World"); //some operations

105
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

String result = future.get();

9.3.2 ThreadPoolExecutor
ThreadPoolExecutor là một Thread pool mở rộng để triển khai các parameters
9.3.3 n
9.4 n
10. Safety Thread
10.1 Giới thiệu
Là một cơ chế giúp bảo vệ dữ liệu. Do các Thread chia sẻ nguồn tài nguyên chung. Do
đó, khi các Thread cùng truy cập, chỉnh sửa giá trị của một đối tượng mà ta không có cơ
chế bảo vệ dữ liệu thích hợp thì sẽ dễ gây ra sai lệch với những kết quả không mong
muốn.
Để làm cho các Thread chương trình của mình an toàn, ta có thể:
 Đồng bộ hóa (Synchronization) là công cụ dễ dàng nhất và được sử dụng rộng
rãi nhất cho Thread Safety trong java.
 Sử dụng các Class Atomic Wrapper từ gói java.util.concurrent.atomic. Ví dụ:
AtomicInteger.
 Sử dụng các khóa từ gói java.util.concurrent.locks.
 Sử dụng các lớp thread safe collection như: Vector, HashTable hoặc các
Collection khác với cơ chế bảo vệ dữ liệu.
 Sử dụng từ khóa “volatile” với các biến để làm cho mọi Thread đọc dữ liệu từ
bộ nhớ, không đọc từ bộ đệm của Thread.
10.2 Synchronized
Đồng bộ hóa là công cụ giúp chúng ta đạt được safety Thread. JVM đảm bảo rằng
Method được đồng bộ chỉ được thực hiện bởi một Thread tại một thời điểm. Các Thread
khác sẽ bị chặn cho tới khi Thread đầu tiên kết thúc hoặc Method ném ra một Exception

106
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Synchronized methods dựa vào sử dụng “intrinsic locks” (Khóa nội tại) hoặc “monitor
locks” (Khóa giám sát). “intrinsic locks” được ẩn bên trong và liên kết với một lớp cụ
thể. “monitor locks” sẽ khóa hoạt động trên một đối tượng cụ thể.
Khi một Thread gọi một Synchronized methods thì nó sẽ nhận được “intrinsic locks”.
Khi Thread thực hiện xong Method thì sẽ trả lại khóa và các Thread khác có thể nhận
khóa và thực hiện Method.
Chúng ta có thể implement synchronization với instance methods, static methods, and
statements (synchronized statements).
Synchronization với instance methods: Khóa một phần tài nguyên (Method) thuộc
về đối tượng.
Synchronization với static methods: Khóa theo Class.
Lưu ý về synchronized statements:
 Khóa tài nguyên cụ thể của Method. Ta phải chỉ định đối tượng cung cấp
“intrinsic locks”.

 Với cách trong ví dụ, “this” chỉ rằng khóa được cung cấp bởi đối tượng hiện tại
của Class, ta chỉ có thể đồng bộ hóa từng phần của Method => Gây tốn kém.
Mặt khác, khi sử dụng “this” để cung cấp “intrinsic locks”, kẻ tấn công có thể
lấy “intrinsic locks” và kích hoạt điều kiện từ chối dịch vụ (denial of service
(DoS) condition) gây ra deadlock
 Dùng một Object để cung cấp “monitor locks” thay cho “this”. Với cách này
thì kẻ tấn công khó có thể truy cập từ bên ngoài để lấy khóa và gây ra deadlock

107
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 n
10.3 Class Atomic
Class Atomic (Atomic Operation: Operation nguyên tử) trong java cung cấp các
Method giúp đạt được Thread-safety trên các biến. Các Class bao gồm: AtomicInteger,
AtomicLong, AtomicBoolean, and AtomicReference.
(Link: AtomicInteger, AtomicLong, AtomicBoolean, và AtomicReference)
Trong Atomic Operation, một bộ xử lý thực hiện tuần tự việc đọc ghi dữ liệu vào một
vị trí trong việc truyền tải dữ liệu giống nhau. Do đó, một Thread không thể đọc hoặc ghi
cho đến khi Atomic Operation hoàn tất.
Một số Method như: get(), set(),…
10.4 Lock từ gói java.util.concurrent.locks
10.4.1 Điểm khác nhau giữa Lock và Synchronized
Lock:
Synchronized:
10.4.2 Lock API
Lock Interface:
 void lock() – Nhận được khóa nếu khóa đó không được sử dụng. Nếu khóa đó
đang được sử dụng thì sẽ bị chặn cho đến khi khóa đó không được sử dụng.
 void lockInterruptibly() – Tương tự như lock(). Tuy nhiên Thread sẽ được tiếp
tục thực thi nếu một Exception java.lang.InterruptedException được ném ra.

108
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 boolean tryLock() – Không bị chặn và sẽ được nhận khóa ngay lập tức, return
true if locking succeeds
 boolean tryLock(long timeout, TimeUnit timeUnit) – Tương tự
tryLock(), nhưng nó sẽ đợi timeout trước khi nhận Lock
 void unlock() – unlocks the Lock instance
ReadWriteLock Interface:
 Lock readLock() – returns the lock that's used for reading
 Lock writeLock() – returns the lock that's used for writing
Lưu ý: Một locked instance nên được mở khóa để tránh deadlock. Ta có thể sử dụng
khối try-catch-finally:

10.4.3 Lock Implementation


ReentrantLock class implements the Lock interface.

109
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

ReentrantReadWriteLock class implements the ReadWriteLock interface.


StampedLock (Java 8), hỗ trợ cả khóa đọc và ghi. Tuy nhiên, Các Method lấy lại khóa
return một stamp được sử dụng để phát hành khóa hoặc để kiểm tra xem khóa có còn hợp
lệ hay không.
10.4.4 Làm việc với Conditions
Condition Class bắt các Thread đợi cho đến khi một điều kiện nào đó xảy ra rồi mới
thực hiện một nhiệm vụ nào đó.
Các Method giao tiếp giữa các luồng:
 Wait(): Giải phóng khóa và đợi cho đến khi một Thread khác gọi notify() hoặc
notifyAll cho Object này
 Wait(long time): Chờ đợi khoảng thời gian
 Notify(): Đánh thức luồng đang chờ trên monitor Object này
 NotifyAll(): Đánh thức tất cả các luồng đang chờ trên monitor của Object này
Condition Class cung cấp một số Method tương tự như: await(), signalAll(), …
10.5 Thread safe Collection
Sử dụng các Collection:
 ConcurrentHashMap: Thread safe mà không synchronize toàn bộ map. Đọc
nhanh, dùng khóa để ghi. Không khóa ở mức Object. Sử dụng multi-locks.
110
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

 SynchronizedHashMap: synchronization mức Object. Sử dụng khóa để đọc và


ghi.
 Vector
 HashTable
 CopyOnWriteArrayList
 CopyOnWriteArraySet
 Stack
Ngoài ra, ta có thể sử dụng các Collection khác với cơ chế bảo vệ dữ liệu bằng cách sử
dụng các Method synchronized với Collection trong Class Collections như:
 synchronizedCollection():
Collections.synchronizedCollection(Collection<T> c)
 synchronizedList():
List<Integer> syncList = Collections.synchronizedList(new ArrayList<>());
 synchronizedMap():
 synchronizedSortedMap()
 synchronizedSet()
 synchronizedSortedSet()…

10.6 Từ khóa “Vollatide”


Vollatide không Block Thread mà nó bắt các Thread đọc và ghi giá trị biến từ main
memory thay cho CPU cache.
Trong một ứng dụng đa luồng trong đó các luồng hoạt động sử dụng biến non-volatile.
Vì lý do hiệu năng mỗi luồng có thể sao chép các biến từ bộ nhớ chính vào bộ đệm CPU
trong khi làm việc với chúng. Nếu máy tính của chúng ta chứa nhiều CPU, mỗi luồng có
thể chạy trên một CPU khác nhau. Điều đó có nghĩa là, mỗi luồng có thể sao chép các
biến vào bộ đệm CPU của các CPU khác nhau. Với các biến non-volatile, không có gì
đảm bảo khi Máy ảo Java (JVM) đọc dữ liệu từ bộ nhớ chính vào bộ nhớ CPU hoặc ghi
dữ liệu từ bộ nhớ CPU vào bộ nhớ chínhVới các biến non-volatile, không có gì đảm bảo
khi Máy ảo Java (JVM) đọc dữ liệu từ bộ nhớ chính vào bộ nhớ CPU hoặc ghi dữ liệu từ
bộ nhớ CPU vào bộ nhớ chính dẫn đến có thể làm sai lệch giá trị mong muốn.
111
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

Nếu một Thread ghi và các Thread khác đọc => Sử dụng biến vollatide ok. Nhưng nếu
nhiều Thread cùng ghi thì vẫn không chắc chắn rằng giá trị của biến sẽ được như ta mong
muốn.
10.7 Sử dụng từ khóa final
Các Thread có thể dùng chung nhưng không thể thay đổi giá trị cảu biến.

10.8 N
11. Deadlock
DeadLock trong java là một trạng thái trong đó 2 hoặc nhiều thread rơi vào tình trạng
chờ đợi lẫn nhau vì mỗi thread giữ một tài nguyên và chờ đợi tài nguyên từ thread khác.
DeadLock trong java là một trạng thái trong đó 2 hoặc nhiều thread rơi vào tình trạng chờ
đợi lẫn nhau vì mỗi thread giữ một tài nguyên và chờ đợi tài nguyên từ thread khác.

Ví dụ:

112
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core

12. n

113

You might also like