Professional Documents
Culture Documents
Phần 1 Java Core
Phần 1 Java Core
Nội dung
Phần 1: Tổng quan...........................................................................................................7
1. Compiler.................................................................................................................7
2.6 n.................................................................................................................10
4. Memory management............................................................................................22
4.6 n.......................................................................................................................27
5. n.............................................................................................................................27
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.1 Datatypes.........................................................................................................30
2.2 Operator...........................................................................................................31
3.1 Input...........................................................................................................36
3.2 Output........................................................................................................37
3.3 n..................................................................................................................38
5. Keyword in Java....................................................................................................38
5.4 n..................................................................................................................43
6. Java if…else..........................................................................................................43
7. Switch statement...................................................................................................44
8. Loop......................................................................................................................44
8.4. n......................................................................................................................45
9. Array......................................................................................................................45
10. String...................................................................................................................46
11. n...........................................................................................................................49
2
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
1. Giới thiệu..........................................................................................................50
4.4 N......................................................................................................................58
5.2 Đa hình lúc biên dịch (Đa hình compiler hay static polymorphism):. 60
5.4 n..................................................................................................................62
6. n........................................................................................................................62
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.4. n......................................................................................................................70
7. n........................................................................................................................73
Phần 6: Collection.........................................................................................................74
1. Giới thiệu..........................................................................................................74
2. List....................................................................................................................75
2.1 ArrayList....................................................................................................75
2.3 LinkedList..................................................................................................78
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
1. Defaut Method.......................................................................................................88
2. Funcional Interfaces..............................................................................................88
3. Lamda Expressions...............................................................................................88
4. Method References................................................................................................90
5. Stream API............................................................................................................92
5.2 Ví dụ...........................................................................................................94
5.6 n..................................................................................................................97
7. Annotation.............................................................................................................97
9. Optional.................................................................................................................97
10. n...........................................................................................................................97
1. Giới thiệu...............................................................................................................99
2.4 n.....................................................................................................................103
3. Process Schedulers..............................................................................................103
5. Interrupt...............................................................................................................103
9.4 n.....................................................................................................................107
10.2 Synchronized...............................................................................................108
10.8 N..................................................................................................................113
11. Deadlock............................................................................................................113
12. n.........................................................................................................................114
6
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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)
đố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
đượ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
12
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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
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.
20
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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.
22
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
23
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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
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.
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
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
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.
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
31
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
32
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
35
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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.
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)
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.
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
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.
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
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ụ:
45
Đỗ 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
}
}
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
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
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.
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
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
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.
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
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
64
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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
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.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
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:
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).
Ví dụ:
78
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
Kết quả:
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
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
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:
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
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
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.
95
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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.
10. n
96
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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
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.
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.
103
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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.
105
Đỗ Văn Thành – Thanh.dovan9998@gmail.com – Java Core
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:
109
Đỗ 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